三、VueX
分区作者:Cool小陈
1、理解vuex
1-1 vuex 是什么
- 概念:专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
- Github 地址: https://github.com/vuejs/vuex
1-2、图解vuex与全局事件总线的相似性
1-3、 什么时候使用 Vuex
多个组件需要共享数据时 {
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态 }
1-4、求和案例-纯vue版本
1-5、vuex的工作原理
Actions、Mutations、State状态(这三个数据类型都是对象)
这三个东西都得经过store领导
dispatch('jia',2) 第一个jia是这个实现的动作,第二个是动作的值
2、vuex环境搭建
2-1、在vue2中使用npm i vuex 失败原因
在2022年2月7日,vue3成为了默认版本,也就是说现在执行npm i vue,安装的直接就是vue3了,并且vue3成为默认版本的同时vuex也同时进行了更新升级到了最新的vuex4版本,npm i vuex安装的是vuex4,只能在vue3中去使用如果我们在vue2项目中使用vuex4就会出现如图所示报错,简单来说就是
vue2要用vuex3的版本
vue3要用vuex4的版本
2-2、正确安装指令
npm i vuex@3
2-3、后续创建命令
1、在src文件夹下面创建store文件夹,然后再在store文件夹下创建index.js
index.js内容如下:
//该文件用于创建Vuex中最为核心的store //引入vue import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //应用Vuex插件 Vue.use(Vuex) //准备actions——用于响应组件中的动作 const actions = {} //准备mutations——用于操作数据(state) const mutations = {} //准备state——用于存储数据 const state = {} //创建并暴露store export default new Vuex.Store({ actions, mutations, state, })
2、然后在main.js中引入store,并在创建vm实例的句子中添加store、
简约代码
...... //引入store import store from './store' ...... //创建vm new Vue({ el:'#app', render: h => h(App), store })
完整代码
//引入Vue import Vue from 'vue' //引入App import App from './App.vue' //引入插件 import vueResource from 'vue-resource' //引入store import store from './store' //关闭Vue的生产提示 Vue.config.productionTip = false //使用插件 Vue.use(vueResource) //创建vm new Vue({ el:'#app', render: h => h(App), store, beforeCreate() { Vue.prototype.$bus = this } })
2-4、求和案例vuex版
context(ministore,上下文)
如果没有涉及到action(业务逻辑)可以直接调用commit并且调用的符号必须大写
3、VueX基本使用
3-1、vuex开发工具
3-2、vuex基本使用
- 初始化数据、配置
actions
、配置mutations
,操作文件store.js
//引入Vue核心库 import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //引用Vuex Vue.use(Vuex) const actions = { //响应组件中加的动作 jia(context,value){ // console.log('actions中的jia被调用了',miniStore,value) context.commit('JIA',value) }, } const mutations = { //执行加 JIA(state,value){ // console.log('mutations中的JIA被调用了',state,value) state.sum += value } } //初始化数据 const state = { sum:0 } //创建并暴露store export default new Vuex.Store({ actions, mutations, state, })
- 组件中读取vuex中的数据:
$store.state.sum
- 组件中修改vuex中的数据:
$store.dispatch('action中的方法名',数据)
或$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch
,直接编写commit
4、getters的使用
- 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
- 在
store.js
中追加getters
配置
...... const getters = { bigSum(state){ return state.sum * 10 } } //创建并暴露store export default new Vuex.Store({ ...... getters })
- 组件中读取数据:
$store.getters.bigSum
5、四个map方法的使用
- mapState方法:用于帮助我们映射
state
中的数据为计算属性
computed: { //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), },
- mapGetters方法:用于帮助我们映射
getters
中的数据为计算属性
computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) },
- mapActions方法:用于帮助我们生成与
actions
对话的方法,即:包含$store.dispatch(xxx)
的函数
methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }
- mapMutations方法:用于帮助我们生成与
mutations
对话的方法,即:包含$store.commit(xxx)
的函数
methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
6、模块化+命名空间
- 目的:让代码更好维护,让多种数据分类更加明确。
- 修改
store.js
const countAbout = { namespaced:true,//开启命名空间 state:{x:1}, mutations: { ... }, actions: { ... }, getters: { bigSum(state){ return state.sum * 10 } } } const personAbout = { namespaced:true,//开启命名空间 state:{ ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { countAbout, personAbout } })
- 开启命名空间后,组件中读取state数据:
//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
- 开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum'])
- 开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
- 开启命名空间后,组件中调用commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
7、耦合性
耦合性,指的是组件间依赖关系的强弱程度
这里两个组件组件直接耦合性从“内容耦合”(一个模块直接使用另一个模块数据)
"控制耦合"(一个模块调用另一模块时,传递的是控制信号,被调用的模块根据控制信号的值,有选择的执行功能),所以,解耦成立
四、vue-router
分区作者:Cool小陈
1、路由
1-1、路由的理解
1-1.1、vue-router的理解
vue 的一个插件库,专门用来实现 SPA 应用
1-1.2、生活中的路由器与编码中的路由
- 生活中的路由器是为了实现多台设备同时上网
网络异常,图片无法展示| - 编码里的路由器是为了实现SPA(single page web application)应用的切换
网络异常,图片无法展示|
1-1.3、对SPA应用的理解
- 单页 Web 应用(single page web application,SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新。
- 数据需要通过 ajax 请求获取。
1-2、路由的理解
1-2.1、什么是路由?
- 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
- key 为路径, value 可能是 function 或 component
1-2.2、路由分类
1、后端路由:
1)理解:value 是 function, 用于处理客户端提交的请求。
2)工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数 来处理请求, 返回响应数据。
2、前端路由:
1)理解:value 是 component,用于展示页面内容。
2)工作过程:当浏览器的路径改变时, 对应的组件就会显示。
1-3、基本使用
- 安装vue-router,命令:
npm i vue-router
2022年2月7日以后,vue-router的默认版本为4版本,并且vue-router4只能在vue3中去使用
vue-router3才能在vue2中,所有我们要指定版本去安装:npm i vue-router@3
- 引入VueRouter:
import VueRouter from 'vue-router'
- 应用插件:
Vue.use(VueRouter)
- 编写router配置项:
//引入VueRouter import VueRouter from 'vue-router' //引入Luyou 组件 import About from '../components/About' import Home from '../components/Home' //创建router实例对象,去管理一组一组的路由规则 const router = new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home } ] }) //暴露router export default router
- 实现切换(active-class可配置高亮样式)
<router-link active-class="active" to="/about">About</router-link>
- 指定展示位置
<router-view></router-view>
2.几个注意点
1、路由组件通常存放在pages
文件夹,一般组件通常存放在components
文件夹。
2、通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
3、每个组件都有自己的$route
属性,里面存储着自己的路由信息。
4、整个应用只有一个router,可以通过组件的$router
属性获取到。
3.嵌套路由(多级路由)
- 配置路由规则,使用children配置项:
routes:[ { path:'/about', component:About, }, { path:'/home', component:Home, children:[ //通过children配置子级路由 { path:'news', //此处一定不要写:/news component:News }, { path:'message',//此处一定不要写:/message component:Message } ] } ]
- 跳转(要写完整路径):
<router-link to="/home/news">News</router-link>
4.路由的query参数
- 传递参数
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法 --> <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }" >跳转</router-link>
- 接收参数:
$route.query.id $route.query.title
5.命名路由
- 作用:可以简化路由的跳转。
- 如何使用
- 给路由命名:
{ path:'/demo', component:Demo, children:[ { path:'test', component:Test, children:[ { name:'hello' //给路由命名 path:'welcome', component:Hello, } ] } ] } a. 简化跳转: <!--简化前,需要写完整的路径 --> <router-link to="/demo/test/welcome">跳转</router-link> <!--简化后,直接通过名字跳转 --> <router-link :to="{name:'hello'}">跳转</router-link> <!--简化写法配合传递参数 --> <router-link :to="{ name:'hello', query:{ id:666, title:'你好' } }" >跳转</router-link>
6.路由的params参数
- 配置路由,声明接收params参数
{ path:'/home', component:Home, children:[ { path:'news', component:News }, { component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', //使用占位符声明接收params参数 component:Detail } ] } ] }
- 传递参数
<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="/home/message/detail/666/你好">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:666, title:'你好' } }" >跳转</router-link>
- 接收参数:
$route.params.id $route.params.title
7.路由的props配置
作用:让路由组件更方便的收到参数
{ name:'xiangqing', path:'detail/:id', component:Detail, //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件 // props:{a:900} //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件 // props:true //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件 props(route){ return { id:route.query.id, title:route.query.title } //简单写法,结构赋值 //props({query}){ // return { // id:query.id, // title:query.title // } //简单写法,结构赋值的连续写法 //props({query:{id,title}}){ // return { // id, // title // } } }
8.<router-link>
的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为
push
和replace
,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
- 如何开启
replace
模式:<router-link replace .......>News</router-link>
9.编程式路由导航
- 作用:不借助
<router-link>
实现路由跳转,让路由跳转更加灵活 - 具体编码:
//$router的两个API this.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.forward() //前进 this.$router.back() //后退 this.$router.go(n) //可前进也可后退,里面要加参数正数前进,负数后退
10.缓存路由组件
- 作用:让不展示的路由组件保持挂载,不被销毁。
- 具体编码:
<keep-alive include="News"> <router-view></router-view> </keep-alive>
11.两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
12.路由守卫
12-1、作用:对路由进行权限控制
12-2、分类:全局守卫、独享守卫、组件内守卫
12-2-1、全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach,全局前置守卫',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'at1'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 //全局后置守卫没有next router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
12-2-2、独享守卫:
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'at1'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
12-2-3、组件内守卫:
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }
13.路由器的两种工作模式
13-1、hash值
对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
- hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
13-2、服务器部署
生产模式
npm run build
部署服务器
node express步骤
npm init
//输入包名字 atguigu_test_server
npm i express 新建server.js 在server.js中输入 const express = require('express') const app = express() //后面创建了static后解开 //app.use(express.static(__dirname+'/static')) app.get('/person',(req,res))=>{ res.send{( name:'tom', age:18 )} } app.listen(5005,(err)=>{ if(!err) console.log('服务器启动成功了!') })
编辑好代码后输入在终端中输入node server启动服务器
在node下创建静态页面
13-3、解决在history模式中404的问题
npm i connect-history-api-fallback
引入
const history =require('npm i connect-history-api-fallback')
然后使用插件
app.use(history())
13-5、路由器工作的两种模式
- hash模式:
- 地址中永远带着#号,不美观 。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
五、Element UI 组件库
分区作者:Cool小陈
1、Vue UI组件库
1-1、移动端常用 UI 组件库
- Vant https://youzan.github.io/vant
- Cube UI https://didi.github.io/cube-ui
- Mint UI http://mint-ui.github.io
1-2、PC 端常用 UI 组件库
- Element UI https://element.eleme.cn
- IView UI https://www.iviewui.com
2、Element UI 安装
2-1、npm 安装
推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
npm i element-ui -S
2-2、CDN
<!-- 引入样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <!-- 引入组件库 --> <script src="https://unpkg.com/element-ui/lib/index.js"></script>
2-3、Element-UI引入方式
2-3-1、完整引入
在 main.js 中写入以下内容:
//引入Vue import Vue from 'vue' //引入App import App from './App.vue' //引入ElementUI组件库 import ElementUI from 'element-ui'; //引入ElementUI全部样式 import 'element-ui/lib/theme-chalk/index.css'; //应用ElementUI Vue.use(ElementUI); //创建vm new Vue({ el:'#app', render: h => h(App), })
2-3-2、按需引入
借助 [babel.config.js,我们可以只引入需要的组件,以达到减小项目体积的目的。
module.exports = { presets: [ '@vue/cli-plugin-babel/preset', ["@babel/preset-env", { "modules": false }], ], plugins:[ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:
import Vue from 'vue'; import App from './App.vue'; //按需引入 import { Button, Select } from 'element-ui'; //应用ElementUI //格式:Vue.component(Button.name, Button); Vue.component(el-button, Button); //格式:Vue.component(Select.name, Select); Vue.component(el-select, Select); /* 或写为 * Vue.use(Button) * Vue.use(Select) */ //创建vm new Vue({ el: '#app', render: h => h(App) });