文章目录
一、环境准备
前提:
# 安装node环境node -vnpm -v# crm开发定制卸载旧脚手架工具npm uninstall vue-cli -goryarn global remove vue-cli# crm开发定制安装新版的脚手架工具 指定版本@vue/cli@版本号npm install -g @vue/cli
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
创建项目
vue create vue3
- 1
Vue CLI v4.5.14┌─────────────────────────────────────────────┐│ ││ New version available 4.5.14 → 4.5.15 ││ Run yarn global add @vue/cli to update! ││ │└─────────────────────────────────────────────┘// 1.手工模式? Please pick a preset: Manually select features// 2.安装 Router, Vuex, CSS 插件? Check the features needed for your project: Choose Vue version, Babel, Router, Vuex, CSS Pre-processors, Linter// 3. vue3.x版本? Choose a version of Vue.js that you want to start the project with 3.x// 4. 选择hash模式 crm开发定制默认历史模式? Use history mode for router? (Requires proper server setup for index fallback in production) No// 5. 选择css插件Sass/SCSS? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)// 6. crm开发定制格式化配置祖安泽标准? Pick a linter / formatter config: Standard? Pick additional lint features: Lint on save? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files// 7. crm开发定制不保存为模板,crm开发定制立即创建项目? Save this as a preset for future projects? (y/N) n
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
二、核心组件
2.1.
安装 axios
使用axios发送ajax请求
npm install axios --save
- 1
utils/request.js
import axios from 'axios'const instance = axios.create({ baseURL: 'https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd', timeout: 10000})export const get = (url, params = {}) => { return new Promise((resolve, reject) => { instance.get(url, { params }).then((response) => { resolve(response.data) }, err => { reject(err) }) })}export const post = (url, data = {}) => { return new Promise((resolve, reject) => { instance.post(url, data, { headers: { 'Content-Type': 'application/json' } }).then((response) => { resolve(response.data) }, err => { reject(err) }) })}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
后续更新集成请求拦截和响应拦截+模块单独api
案例:获取博文发布作者姓名
<template> <div class="about"> <h1 @click="handleClick">This is an about page</h1> <button @click="getBlogData">获取博文数据</button> </div> <div>{{ name }}</div></template><script>import { toRefs } from 'vue';import { useStore } from 'vuex';export default { name: 'about', setup() { const store = useStore(); // 从store.state把name解构出来 const { name } = toRefs(store.state); const handleClick = () => { // 异步修改数据 store.dispatch('getData', 'hello aync'); // 同步修改数据 // store.commit('changeName', 'hello2'); }; const getBlogData = () => { store.dispatch('getBlogData'); }; return { name, handleClick, getBlogData }; },};</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
大家可以直接使用我的调用测试地址,自己的地址会有跨域问题
import { createStore } from 'vuex';import axios from 'axios';// VueX 数据管理框架// VueX 创建一个全局唯一的仓库,用来全局的数据export default createStore({ state: { name: 'dell', }, mutations: { changeName(state, val) { state.name = val; }, }, actions: { // 异步逻辑 getBlogData(store) { axios .get( 'https://www.fastmock.site/mock/a4701044176a98816d53ce26897cdd3b/api/hxq' ) .then((res) => { console.log(res); const name = res.data.name; store.commit('changeName', name); }); }, // 修改名字 getData(store, val) { setTimeout(() => { store.commit('changeName', val); }, 2000); }, }, modules: {},});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
后期,api接口具体调用会api目录下的模块具体的xx.js中,然后在,store的index模块的actions下面调用此方法即可
2.2. vuex
store/index.js
VueX 数据管理框架VueX 创建一个全局唯一的仓库,用来全局的数据,一处修改,全局立即生效数据声明和数据获取使用:数据放到state里面通过计算属性获取到数据computed: { myName() { return this.$store.state.name; } }数据修改声明一个事件触发一个 /** * 1.dispatch方法,派发一个action,名字叫做change * 2.vuex中actions就会感知到change 这个action,执行store中actions下面change的方法(在actions中的方法不能直接修改数据,必须通过提交一个commit发送请求) * 3.在actions下面change的方法内部,提交一个commit 叫做change的数据改变方法 * 4.mutation 感知到提交的mutation改变,执行change方法,改变数据 * 5. */ state中的数据只能在mutations中去修改 mutation只执行同步的代码逻辑 actions中写异步的逻辑(不做数据修改具体操作,只是发送commit请求) 如果不需要异步操作:也可以 this.$store.commit('change', 'hello word'); mutations下的change方法也会感知到,直接修改数据 dispatch是和actions做关联的 commit是和mutations做关联的 一般 mutations中封装同步代码 actions封装异步代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
传统方式使用
import { createStore } from 'vuex';// VueX 数据管理框架// VueX 创建一个全局唯一的仓库,用来全局的数据export default createStore({ state: { name: 'dell', }, mutations: { // 第4步,对应的mutation 被执行 change(state, val) { // 第5步,在mutation里面修改数据 state.name = val; }, }, actions: { // 第2步,store感知到你触发一个change的action,执行change方法 change(store, val) { // 第3步,提交一个commit 触发一个mutation setTimeout(() => { store.commit('change', val); }, 2000); }, }, modules: {},});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
about.vue
<template> <div class="about"> <h1 @click="handleClick">This is an about page</h1> <div>{{ myName }}</div> </div></template><script>export default { name: 'about', computed: { myName() { return this.$store.state.name; }, }, methods: { handleClick() { /** * 1.dispatch方法,派发一个action,名字叫做change * 2.感知change 这个action,执行store中actions下面change的方法 * 3.commit 提交一个叫做change的数据改变 * 4.mutation 感知到提交的mutation改变,执行change方法,改变数据 * 5. */ this.$store.commit('change', 'hello word'); // this.$store.dispatch('change', 'hello word'); }, },};</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
compositionAPI方式
从vuex中引入useStore函数,获取全局数据对象
然后通过useStore获取Store,使用commit调用同步方法改数据
使用dispatch调用异步方法改数据
import { createStore } from 'vuex';// VueX 数据管理框架// VueX 创建一个全局唯一的仓库,用来全局的数据export default createStore({ state: { name: 'dell', }, mutations: { changeName(state, val) { console.log; val; state.name = val; }, }, actions: { // 异步逻辑 getData(store, val) { setTimeout(() => { store.commit('changeName', val); }, 2000); }, }, modules: {},});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
about.vue
<template> <div class="about"> <h1 @click="handleClick">This is an about page</h1> </div> <div>{{ name }}</div></template><script>import { toRefs } from 'vue';import { useStore } from 'vuex';export default { name: 'about', setup() { const store = useStore(); // 从store.state把name解构出来 const { name } = toRefs(store.state); const handleClick = () => { // 异步修改数据 store.dispatch('getData', 'hello aync'); // 同步修改数据 // store.commit('changeName', 'hello2'); }; return { name, handleClick }; },};</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
2.3.
import { createRouter, createWebHashHistory } from 'vue-router'const routes = [{ path: '/', name: 'Home', component: () => import(/* webpackChunkName: "home" */ '../views/home/Home') },{ path: '/cartList', name: 'CartList', component: () => import(/* webpackChunkName: "cartList" */ '../views/cartList/CartList') },{ path: '/orderConfirmation/:id/:addressId?', name: 'OrderConfirmation', component: () => import(/* webpackChunkName: "orderConfirmation" */ '../views/orderConfirmation/OrderConfirmation') }, { path: '/orderList', name: 'OrderList', component: () => import(/* webpackChunkName: "orderList" */ '../views/orderList/OrderList') },{ path: '/shop/:id', name: 'Shop', component: () => import(/* webpackChunkName: "shop" */ '../views/shop/Shop') }, { path: '/register', name: 'Register', component: () => import(/* webpackChunkName: "register" */ '../views/register/Register'), beforeEnter(to, from, next) { const { isLogin } = localStorage; isLogin ? next({ name: 'Home'}): next(); } }, { path: '/login', name: 'Login', component: () => import(/* webpackChunkName: "login" */ '../views/login/Login'), beforeEnter(to, from, next) { const { isLogin } = localStorage; isLogin ? next({ name: 'Home'}): next(); } }, { path: '/chooseAddressList/:shopId', name: 'ChooseAddressList', component: () => import(/* webpackChunkName: "chooseAddressList" */ '../views/chooseAddressList/ChooseAddressList'), },{ path: '/myAddressList', name: 'MyAddressList', component: () => import(/* webpackChunkName: "myAddressList" */ '../views/myAddressList/MyAddressList'), }, { path: '/upsertAddress/:id?', name: 'UpsertAddress', component: () => import(/* webpackChunkName: "upsertAddress" */ '../views/upsertAddress/UpsertAddress'), }, { path: '/person', name: 'PersonalInfo', component: () => import(/* webpackChunkName: "person" */ '../views/personalInfo/PersonalInfo'), }]const router = createRouter({ history: createWebHashHistory(), routes})router.beforeEach((to, from ,next) => { const { isLogin } = localStorage; const { name } = to; const isLoginOrRegister = (name === "Login" || name === "Register"); (isLogin || isLoginOrRegister) ? next() : next({ name: 'Login'});})export default router
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
<template> <router-view /></template><script>export default { name: 'App',}</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
参数传递
,{ path: '/shop/:id', name: 'Shop', component: () => import(/* webpackChunkName: "shop" */ '../views/shop/Shop') }
- 1
- 2
- 3
- 4
- 5
参数接收
<template> <div class="wrapper"> <div class="title"> <div class="iconfont title__back" @click="handleBackClick" ></div> <div class="title__text">管理收货地址</div> <div class="title__add" @click="handleAddClick">新建</div> </div> <Address v-for="address in addressList" :key="address._id" :address="address" @click="() => handleUpdateClick(address._id)" /> </div></template><script>import Address from '../../components/Address'import useCommonAddressEffect from '../../effects/addressEffect'import { toRefs } from 'vue'import { useStore } from 'vuex'import { useRouter } from 'vue-router'export default { name: 'MyAddressList', components: { Address }, setup() { const store = useStore() const router = useRouter() const { addressList } = toRefs(store.state) const { getAddressList } = useCommonAddressEffect() getAddressList(true) const handleBackClick = () => { router.back() } const handleAddClick = () => { router.push({ name: 'UpsertAddress'}) } const handleUpdateClick = (addressId)=> {router.push(`/upsertAddress/${addressId}`)} return { addressList, handleBackClick, handleAddClick, handleUpdateClick } }}</script><style lang="scss" scoped></style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47