文章目录
一、Vue 基础语法学习1、Vue 语法指令2、Vue 实例属性(1)el(2)data(3)methods(4)computed3、事件修饰符4、按键修饰符5、Vue实例的生命周期6、ES6语法的基本使用(1)声明变量使用let、const(2)箭头函数的使用(3)模板字符串(4)变量名与参数名一致只写一个二、Vue 组件学习1、Vue 标准开发方式2、组件的好处3、组件的使用(1)全局组件定义一个全局组件使用全局组件(2)局部组件(3)组件间传参传递参数传递事件4、Slot 插槽的使用三、Vue Router 路由学习(1)引入 Vue Router(2)创建路由规则并注册到vue实例中(3)展示路由组件,添加切换路由的链接(4)效果(5)切换路由的方式1、使用a标签2、使用 router-link 标签3、在 js 事件中 切换路由(6)路由之间参数传递1、queryString 方式传参2、RestFul 方式传参(7) 嵌套路由四、Vuex 状态管理器(1)简介(2)在Vue Cli 中使用 Vuex1、安装Vuex2、配置 Vuex(3)store 对象中的属性以及调用1、state2、multations3、getters一、Vue 基础语法学习
直接<script> 引入使用
<script type="text/javascript" src="../js/vue.js"></script>
初体验
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>初识Vue</title><!-- 全局引入vue.js --><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 一个容器 --><div id="root"><h1>Hello,{{message}}</h1><h1>我的年龄是:{{age}}</h1></div><script>// 创建vue实例var a = new Vue({el:'#root', // el通常指定当前vue实例为那个容器服务,指定让vue实例与容器建立联系data:{// data中用于存储数据,数据供el属性所指定的容器去使用,值我们暂时先写成一个对象message:'RAIN7',age:28}})</script></body></html>
1、想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象{el:data:}2、root容器中的代码依然是html,只不过混入了一些特殊的模板语法3、root容器中的代码称为 Vue 模板(template)
1、Vue 语法指令
v-text
相当于 innertext,填充text内容,内容通常放在 Vue实例的data中
v-html
相当于 innerHTML,填充html语句,内容通常放在 Vue实例的data中
v-on
绑定事件,就是绑定一个函数,这个函数写在 Vue实例的 methods 中
事件的简化绑定
v-on:click=“a()”,这种形式的代码可以写成 @click
v-on:mouseover=“b()”,@mouseover
v-if v-elif v- else
如果后面的为真,那么才进行执行显示这里的标签
v-show
绑定 style的display属性,只要为真,那么显示,只要为假,那么隐藏
v-bind
绑定该标签的除value外的所有属性 v-bind:标签属性=“vue里的内容”
<h1 v-bind:style="color">标题</h1><--!v-bind的另外一种写法 :标签属性="vue实例内容" ,: 就代表v-bind><h1 :style="color">标题</h1>new Vue({data:{color:"color:blue"}})
v-for
执行遍历操作,所属的标签的下级标签可以直接引用对象进行遍历
value,key,index in user// 遍历对象item in items // 遍历数组
<table><tr v-for="content,index in list"> // 写成 item in items<th>{{content}}</th></tr></table>new Vue({data:{list:["1","2","3","4"]}})
v-model
绑定该标签的value属性,一般用于表格 input
<input type="text" v-model="aa">new Vue({data:{aa:"我是谁"}})
2、Vue 实例属性
(1)el
相当于元素选择器,绑定容器
(2)data
里面放入定义好的数据,data:{name:“”,list:[{id:“”,name:“”}]},全部都写成json格式的
(3)methods
里面放的都是方法
(4)computed
computed是实例中的属性,将一些需要多次重复计算的函数放到这里,多次取的时候实际只算一次,其余每次相当于都缓存
<h1 style="text-align: center">{{sub()}}--{{sub()}}--{{sub()}}</h1>// 这试过了,如果接收方法返回的值必须要写括号,才能接收到new Vue({data:{count:10}, methods:{sub(){return this.count+10;}}})
打印了三次log语句,计算的时候没有缓存
<h1 style="text-align: center">{{sub}}--{{sub}}--{{sub}}</h1>// 这里computed 表示缓存的属性,不需要写()new Vue({data:{count:10}, methods:{},computed:{sub(){return this.count+10;}}})
只打印了一次log语句,第一次计算的时候就开始缓存了
3、事件修饰符
v-on:click.stop:=" " @click.stop
阻止绑定的标签发生事件冒泡
v-on:click.prevent=“” @click.prevent
用来阻止标签的默认行为,就是写了个href,不跳转,只执行事件
v-on:click.self=“” @click.self
只监听自身标签触发的事件
v-on:click.once=“” @click.once
自身标签触发的事件只发生一次
4、按键修饰符
用来对键盘按键进行修饰,修饰符
@keyUp: 键盘任意键抬起发生事件
@keyDown: 键盘任意键按下发生事件
@keyUp:“enter”
对键盘回车键进行修饰
@KeyUp:“tab”
对键盘切换tab键修饰
5、Vue实例的生命周期
什么是Vue的生命周期?
Vue实例对象从创建到运行,再到销毁的过程
什么是生命周期钩子?
就是生命周期函数。特点:伴随着Vue实例的生命周期过程自动触发的,不需要认为手动触发的函数
生命周期方法在vue实例中,created()在渲染之前,一般方法内部发送axios请求返回后端数据给Vue中的data数据进行赋值,以实现前后端数据的交互。
<script>// 创建vue实例var a=new Vue({el:"",data:{},methods:{},computed:{},// 初始化阶段beforeCreate(){// 第一个生命周期函数,这个函数执行时,仅仅完成自身内部事件以及生命周期函数的注入工作console.log("beforeCreate:==========")},created(){// 第二个生命周期函数,这个函数执行时,完成自身内部事件、生命周期函数、自定义数据data\methods\computed注入以及语法校验工作console.log("created:==========")},beforeMount(){// 第三个生命周期函数,这个函数执行的时候,el执行HTML还是一个原始模板,并没有完成数据渲染工作(模板指定代码与 vue数据不绑定)console.log("beforeMount:==========")},mounted(){// 第四个生命周期函数,vue已经完成了 对 template 和 el的渲染工作console.log("mount:==========")},// 运行阶段beforeupdate(){// 第五个生命周期函数,这个函数执行时,data数据发生改变,此时页面数据还是原始数据console.log("beforeUpdate:==========")},updated(){//第六个生命周期函数,这个函数执行时,data数据 已经和 页面数据 保持一致了console.log("updated:==========")},// 销毁阶段 , vue并不会自动销毁,只有手动调用 a.$destory()才会销毁beforeDestroy(){// 销毁的第一个生命周期函数。这个函数指定的时候,vue实例才刚刚开始销毁console.log("beforeDestroy:==========")},destroyed(){// 销毁阶段的第二个生命周期函数,这个函数执行,vue实例已经销毁全部console.log("destroyed:==========")}})</script>
6、ES6语法的基本使用
(1)声明变量使用let、const
以前都用 var 来声明一个变量,但是 var 的作用域有大问题
for(var i=0;i<10;i++){console.log(i); }console.log(i);
按道理应该打印到9 就结束了,但是出了for循环发现 i还行进行使用,这就不太好了
es6 所有的变量使用let声明, 常量 使用const进行声明,常量就像 static final 一样
const 通常来表示 对象、数组,那之前说了他表示常量,这里是 数组和对象都是地址不变,但是属性可以变,所以const 可以表示。
let声明的变量作用域在于 代码块内部,除了代码块就结束了。
(2)箭头函数的使用
这个东西怎么说呢,就是和java的lamda表达式很像,使用在匿名函数上。而匿名函数通常是作为一个参数进行使用的。
以前的匿名函数
function(){}
现在的箭头函数
(参数)=>{函数体}
有一个注意的语法规则
1、当没有参数或者参数大于一个的时候,必须得加(),当参数只有一个是,可以不写括号
2、当函数体中只有一行代码时,可以不写{}
最重要的特性
3、箭头函数没有this,外部谁是实例谁就是this,而之前的匿名函数的this指向window。
上面这个特性就极大的方便了我们使用axios
之前我们要在 axios内部使用 匿名函数参数,必须在外部写_this
var _this = this;
然后在函数内部使用 _this 来指向vue实例
new Vue({el:"#app"data:{count:1}created(){var _this = this;axios.get("url").then(function(response){_this.count=2; // 必须使用 _this 才能代表 Vue实例});}})
es6箭头函数的使用
写 axios的时候,内部可以使用箭头函数,this可以直接用
new Vue({el:"#app"data:{count:1}created(){axios.get("url").then(()=>this.count=2);// 0个参数,一个语句// 没有参数时前面必须加(),后面函数体一个语句可以不写{}axios.get("url").then(resp=>this.count=2);// 1个参数,一条语句// 一个参数前面() 可以省略,后面{} 省略axios.get("url2").then(resp=>{this.count=2; this.count=3}); //前面() 省略,后面{}多条语句不能省略}})
(3)模板字符串
以前我们使用语法
let html = "<button οnclick=''>点我</button> <div class='' style='text-align: center;color: red'>"
如果我们在内部还要用 “” ,就需要转义 ,有时候需要用到外部属性做参数,还得拆分拼接,即为不方便。
es6 定义了 `` ,在这个符号内部进行前端代码 有提示能和在外部使用一样的效果
let html=`<div><h1>这是模板字符串的代码</h1></div>`
在内部使用,内容还可以格式化
<div id="app"></div><script>let html = `<div><h1>这的语句!</h1><table><th>年龄</th><tr>性别</tr><tr>薪水</tr><tr>姓名</tr><tr>编辑</tr></table></div>`document.querySelector("#app").innerHTML=html;</script>
(4)变量名与参数名一致只写一个
举个我们以前语法的例子
let name = '小陈';let age = 19;let salary = 2300.50;let body = {name:name,// 参数名name 对应 name变量age:age, // 同上salary:salaey}
而现在要求我们如果变量名和参数名一致的话,把参数名赋给变量名的时候,就写一个名字即可
let name = '小陈';let age = 19;let salary = 2300.50;let body = {name,age,salary}; // 这与上面那个例子时一样的效果,重点参数名与变量名保持一致
二、Vue 组件学习
前期主要学基础语法。
1、Vue 标准开发方式
组件就是用来减少Vue实例对象中的代码量而存在的,日后在使用Vue开发的过程中,可以根据不同业务功能将页面划分不同的组件,然后由多个组件去完成页面的布局,便于使用Vue进行开发页面管理,方便后期维护
其实Vue推荐的开发方式是 SPA, Simple Page (Web)Application, 单页面网页应用,建议Vue开发是单页面的web应用。
什么是单页面,日后项目中只有一个 页面Index.html,那么一个页面能搞定这些吗?
首先解释为什么推荐SPA的开发方式?
之前的开发
1、引入 vue.js 文件
2、在页面中创建vue实例对象,一个页面最多只能绑定一个Vue实例
现在的开发
一个应用中只能存在一个Vue实例,
如果多个页面对应多个Vue实例的话,那么一个页面就有一个实例,复杂的项目有成百上千个Vue实例怎么交换数据?同时项目之间的vue管理非常复杂,同时项目启动的时候每次vue实例都会消耗时间,拖低系统运行时间。
那么一个页面怎么完成那么多功能模块呢?这就靠Vue的其他生态:组件以及路由了。
2、组件的好处
组件减少了 Vue根实例的代码量
一个组件负责完成项目中的一个功能或者一组功能实现业务功能的隔离,完成解耦
组件还可以在Vue里实现复用
3、组件的使用
在用的时候,我们需要转换一个思想,就是一个组件就相当于一个小的vue实例对象,他和一个vue实例对象那个中的使用、配置很多都是相同的。
(1)全局组件
比如说一个导航栏,我们想要在所有的模块中作为一个公共的部分进行加载。
全局组件可以在所有组件上使用。
定义一个全局组件
ponent()// 使用Vue直接注册根实例组件,属于所有组件共有的
使用全局组件
(1)component 这个方法,第一个参数表示组件名,有什么用呢?就是说我们组件写好了,放在vue的其他组件的那个位置展示呢? 在对应的位置 直接使用<组件名> </组件名>这个标签即可,就相当于在这个位置使用组件了。
(2)template,这个属性放的是 组件的所有html代码,必须只有一个根元素,所有代码只能在一个标签(根元素)下包裹着,否则不能解析。
(3)data组件的data和 vue的data要做以区别,就是说在vue中data对应的是很多对象,组件中必须一个函数,返回可以携带要传递的数据。
(4)methods、computed、生命周期函数都和一般的vue实例是一样的。
<script>// 参数1:组件名字 参数2:组件的配置对象ponent("login",{template:`<div><h1>登陆组件|{{aa}}</h1></div>`, props:{},data(){return {aa:"这是全局组件的data数据!"}},methods:{},computed:{},created(){}})// 参数1:组件名字 参数2:组件的配置对象ponent("register",{template:`<div><h1>注册组件</h1></div>`, props:{},data(){return {msg:"这是全局组件的data数据!"}},methods:{},computed:{},created(){}})const a = new Vue({el: "#app",data: {msg: html},methosd: {},computed: {},created() {}})</script>
(2)局部组件
用的最多的就是局部组件,只能在注册组件中使用组件,定义的组件得在在注册组件中 components属性中下声明。components 中可以创建多个局部组件。
该局部组件只能在注册组件中使用
<div id="app"><!-- 局部组件只能在注册的组件中进行使用--><add></add> </div>const add = {template:``,props:[],methods:{},data(){return {}},created(){}}const app = new Vue({el:"#app",data:{msg:"Vue组件使用"},methods:{},computed:{},components:{add // 这是使用了es6的语法相当于 add:add// 如果直接定义的话,是这样写的// add:{ template:``,data(){},...}}})
(3)组件间传参
首先先强调一下,Vue官方说组件之间是单流向传递,只支持父组件传递参数给子组件,但是我们呢也可以通过事件或者插槽的方式在子组件中改变父组件的相关值
传递参数
使用组件的 props 属性传递数据
(1)静态参数
直接在组件的使用处(标签属性),声明静态数据,key=alue,参数值写死表示静态数据,同时在组件定义内部使用props进行接收。
第一步,父类的组件中 在子类组件标签中进行声明传递的静态参数
第二部,子类组件在 props 属性中进行接收参数,接收参数相当于在data中定义了
第三步,在子类template中进行渲染
<div id="app"><h1>{{msg}}</h1><!-- 1、在父类中 传递静态参数--><add title="这是父类传递给子类的静态title参数"></add></div><script>const add = {template:`<div><h1>{{title}}</h1> </div>`,props:["title"], // 2、props 进行接收父类在标签处 声明的title参数}const a = new Vue({el:"#app",data:{msg:"Vue 组件使用"},methods:{},computed:{},components:{add // 注册 add 组件},created(){}})</script>
(2)动态参数
父类在 子类组件的标签中传递的时候,绑定自身的data中的数据,我们就可以动态的通过改变父类的参数,进而改变子类的参数了
<div id="app"><h1>{{msg}}</h1><!-- 绑定name的值--><input type="text" v-model="name"><!-- 在父类中传递动态参数,使用 :接收参数名:绑定参数名--><add :bbb="name"></add></div><script>const add = {template:`<div><h1>{{bbb}}</h1></div>`,props:["bbb"], // props 进行接收父类在标签处 声明的bbb参数}const a = new Vue({el:"#app",data:{msg:"Vue 组件使用",name:""},methods:{},computed:{},components:{add},created(){}})
达成效果,我们在文本框中输入值改变name的值,那么子类组件显示的内容也会发生改变。
传递事件
在标签处声明使用 @组件事件名=父类组件事件名,不需要接收。
@key=value || @传递事件名="父类组件中传递事件名" 前面这个传递事件名是随便起的,在 调用this.$emit()时候才会用,并不是在子组件专门声明的方法
我们在使用的时候,需要用 this.$emit() 进行使用,所以父类的事件需要我们在自己组件的事件中进行调用,同时可以进行传递需要的参数,实现子类组件向父类的参数传递
this.$emit()// 第一个参数是 声明的组件事件名,后面的参数都是要传递的参数
下面是一个 传递事件的案例
解释一下,父类的incrment事件被 子类的aaa事件接收(就相当于换了个名字),在子组件methods中声明的testChild中调用 父类组件的aaa(incrment)事件,传递了一个message参数,父类可以对其进行接收。
最好别换名字都写成一致的,方便管理。
<div id="app"><h1>{{msg}}</h1><input type="text" v-model="name"><!-- 在父类中 传递静态参数--><add count=1 @aaa="incrment"></add></div><script>const add = {template:`<div><h1>{{counter}}</h1><button @click="testChild">点我加一</button></div>`,data(){return {counter:this.count}},props:["count"], // props 进行接收父类在标签处 声明的title参数methods:{testChild(){this.counter++; // 不能对传过来的参数直接++,会报警告,再赋给data中的属性即可this.$emit("aaa","这是子类传递给父类的参数内容!")// 通过该条语句调用传递过来的 事件,并且可以实现子类传递参数给父类}}}const a = new Vue({el:"#app",data:{msg:"Vue 组件使用",name:"",},methods:{incrment(message){console.log(message);}},computed:{},components:{add},created(){}})</script>
4、Slot 插槽的使用
<slot> </slot> 标签写在 组件的 template中,就相当于一个占位符,我们将需要占位的内容放在 组件标签的内部,同时如果是多个内容对多个占位符怎么区分呢?
<slot> 标签有个属性,叫做name,这就叫做具名插槽,在组件标签内部写内容的时候一个插槽放一个容器(只有一个根标签,可以加属性 slot,对应指定 slot 的名字)
举一个例子
<div id="app"><h1>{{msg}}</h1><!-- 在子类组件的标签中放入 传递的插槽内容--><add><h1 slot="slot1">这是插槽1内容!</h1> <h2 slot="slot2">这是插槽2内容!</h2></add></div><script>const add = {template:`<div><h1>{{abc}}</h1><slot name="slot1"></slot><slot name="slot2"></slot></div>`,data(){return {abc:"slot插槽的使用"}}}</script>
此时就能达到效果,将插入的内容展示到页面中
同时插槽也能带给子组件一个好处,就是子组件可以直接使用组件的参数、事件等,不需要传递了
举一个例子
<div id="app"><h1>{{msg}}</h1><!-- 在父类中 传递静态参数--><add><button @click="aaa" slot="slot1">插槽传递的按钮</button></add><!-- 因为子组件中的插槽内容本身就存在与父组件中,可以直接使用父组件的参数、事件等--></div><script>const add = {template:`<div><h1>{{abc}}</h1><slot name="slot1"></slot></div>`,data(){return {abc:"slot插槽的使用"}}}const a = new Vue({el:"#app",data:{msg:"Vue 组件使用",},methods:{aaa(){// 这个方法作用于插槽中的方法alert("父组件的方法通知!");}},computed:{},components:{add},created(){}})</script>
三、Vue Router 路由学习
在上面的组件学习中,我们提到了单页面应用开发,那么我们如果有很多其他功能的页面需要去切换的话,单页面怎么实现切换呢?
先简单说明一下路由的思想,之前我们是把子组件注册到 父组件中进行使用的,通过标签进行显示,现在通过路由管理组件,在vue实例中注册路由管理器,一个路由对应一个组件,我们通过切换路由达到 在一个页面中不同组件显示的效果。
通过 Vue Router 可以将现有的Vue开发便的更加灵活,可以根据前端的url对应在页面中展示不同的组件。
(1)引入 Vue Router
Vue Router的前提是 引入了 Vue.js
<!-- vue.js 源文件 --><script src="/npm/vue/dist/vue.js"></script><!-- vue-router源文件 --><script src="/vue-router/dist/vue-router.js"></script>
(2)创建路由规则并注册到vue实例中
我们在配置路由的时候,path中直接填写相对路径即可,在访问的时候 ,根路由是“#/”,叫做hash路由,我们在后面输入路由,直接匹配到对应的组件。
路由管理器对象是 VueRouter,路由规则属性是 routes
配置好路由管理对象之后,需要将该路由对象注册到 vue实例中
<script>// 一个登陆组件对象const login = {template: `<div><h1>这是登陆的组件,由路由管理器router管理</h1></div>`,}// 一个注册组件对象const reg = {template: `<div><h1>这是注册的组件,由路由管理器router管理</h1></div>`,}const notFound = {template:`<div><h1>404 NOT Found! 输入页面找不到!</h1></div>`}// 配置路由器 管理 组件对象const router = new VueRouter({routes:[// 配置路由规则,放置一个一个规则对象,一个路由对应一个组件{path:"/",redirect:"/login"},// 根路由就是没有匹配路由的界面,路由重定向{path:"/login",component:login,name:"login"},{path:"/reg",component: reg,name:"reg"},{path:"*",component: notFound,name:"notfound"}// 这个对象最好放在最后]})new Vue({el:"#app",data:{},methods:{},router// 将路由管理对象 注册到 vue 实例中})</script>
(3)展示路由组件,添加切换路由的链接
我们在vue的组件中 使用<router-view> 相当于一个占位符,输入路由访问的组件在这个单页面中的这个位置进行展示。相当于之前的子组件标签。
<div id="app"><a href="#/login">登陆组件</a><a href="#/reg">注册组件</a><!-- 路由对应的组件展示的位置,用router-view 表示位置--><router-view></router-view></div>
(4)效果
打开根路由界面,默认重定向到 /login
点击注册组件的超链接,注册组件开始
如果输入没有配置的路由规则的话,那么同意返回的是404组件
(5)切换路由的方式
1、使用a标签
必须加上 #/,表示哈希路由
<!-- 切换路由标签 a 标签必须加入 href中必须写上 #/ 表示哈希路由--><a href="#/login">用户登录</a><a href="#/reg">用户注册</a>
2、使用 router-link 标签
(1)to=“路由路径”,直接加上路由路径即可
<!-- 切换路由标签 router-link 标签必须加入 to属性 to="路由路径"--><router-link to="/login">用户登陆</router-link><router-link to="/reg">用户注册</router-link>
(2):to={path:“”},to属性绑定一个对象,内部写上path属性
to后面跟一个对象,使用vue语法,绑定vue实例中的router对象中的路由规则,:to 需要加冒号
<!-- 切换路由标签完整应该写成一个路由规则的对象--><!-- 如果to后面跟的是一个对象的话,使用的是vue的语法,必须使用属性绑定 :to="{}"--><router-link :to="{path:'/login'}">用户登录</router-link><router-link :to="{path:'reg'}">用户注册</router-link>
(3):to={name:“”}, to属性绑定一个对象,内部写上 name 属性
绑定路由规则对象中的name属性,推荐使用该方式进行绑定路由。
<!-- 名称切换路由,根据路由的name切换不同的组件--><router-link :to="{name:'login'}">用户登录</router-link><router-link :to="{name:'reg'}">用户注册</router-link>
3、在 js 事件中 切换路由
比如说有一种需求,首先进入登陆界面,点击登陆,进入主页,需要给 登陆按钮 绑定一个页面跳转的事件,跳转到主页相关组件的路由。
this.$router
this.$router 表示路由器管理对象,push()负责跳转路由
this.$route
当前路由对象,能拿到当前路由的名字,以及后面携带的参数,等会将传参
我们来实现一个跳转路由的事件
<div id="app"><!-- 路由对应的组件展示的位置,用router-view 表示位置--><router-view></router-view></div><script>// 一个登陆组件对象const login = {template:`<div><form action="">用户名:<input type="text" v-model="user.username">密码:<input type="text" v-model="user.password"><button @click="sumitBtn">点击登陆</button></form></div>`,data(){return {user:{username:"",password:""}}},methods:{sumitBtn(){if(this.user.username==="admin" && this.user.password==="admin"){// 后台校验伪代码this.user.username="";this.user.password="";// 跳转页面到主页组件this.$router.push({name:"index"});// 跳转到 /index 路由下}}}}const index = {template: `<div><h1>这是主页所有组件!</h1></div>`}// 配置路由器 管理 组件对象const router = new VueRouter({routes: [// 配置路由规则,放置一个一个规则对象,一个路由对应一个组件{path: "/", redirect: "/login"},// 根路由就是没有匹配路由的界面,路由重定向{path: "/login", component: login, name: "login"},{path: "/index",component: index,name:"index"},]})new Vue({el: "#app",data: {},methods: {},router// 将路由管理对象 注册到 vue 实例中})</script>
我们在来写两个按钮的事件互相跳转路由
<div id="app"><button @click="jumpLogin">用户登录</button><button @click="jumpRegister">用户注册</button><!-- 路由对应的组件展示的位置,用router-view 表示位置--><router-view></router-view></div><script>// 一个登陆组件对象const login = {template: `<div><h1>这是登陆的组件,由路由管理器router管理</h1></div>`,}// 一个注册组件对象const reg = {template: `<div><h1>这是注册的组件,由路由管理器router管理</h1></div>`,}// 一个找不到页面的组件对象const notFound = {template:`<div><h1>404 NOT Found! 输入页面找不到!</h1></div>`}// 配置路由器 管理 组件对象const router = new VueRouter({routes:[// 配置路由规则,放置一个一个规则对象,一个路由对应一个组件{path:"/",redirect:"/login"},// 根路由就是没有匹配路由的界面,路由重定向{path:"/login",component:login,name:"login"},{path:"/reg",component: reg,name:"reg"},{path:"*",component: notFound,name:"notfound"}// 这个对象最好放在最后]})new Vue({el:"#app",data:{},methods:{jumpLogin(){// 点击按钮进行跳转到 /login 对应的组件并显示在 <router-view>this.$router.push("/login");},jumpRegister(){// 点击按钮进行跳转到 /reg 对应的组件并显示在 <router-view>this.$router.push("/reg");}},router// 将路由管理对象 注册到 vue 实例中})</script>
解决同一个路由器多次切换报错的问题
现在的vue router 很多都版本更新了,没有这个问题,老版本有 点击跳转到同一个路由,那么浏览器会报错
const originPush = VueRouter.prototype.push;VueRouter.prototype.push = function push(location){return originPush.call(this,location).catch(err => err)};
如果不配置的话,每次跳转的时候做一次判断,当当前路由不为XX时,进行跳转
if(this.$route.name!='Login'){this.$router.push({name:'Login'});// 使用名称跳转路由}
(6)路由之间参数传递
传递参数有两种
queryString , problem.html?id=1 参数在路由后面用?连着
RestFul, problem.html/admin 参数直接在后面通过/ 路径传递
1、queryString 方式传参
举一个例子,前端的登陆,要把 username\passsoword 通过queryString 的方式传递给后端进行校验以及判断,那么怎么传递呢?
我们将设输入链接为/login?name=xiaochen&password=123
,查看this.$route发现又以下属性
发现我们传递的参数可以通过this.$route.query.key拿到路由后面的参数
给路由传参数,可以直接在path后面追加
<router-link to="/login?username=admin&password=admin"></router-link>
通过对象的方式进行传递参数
<router-link to="{name:'login',query:{username:'admin',password:'admin'}}"></router-link>
2、RestFul 方式传参
这种风格,路由和后面的参数为一体的,必须在路由规则处进行声明,通过 :key/:key 的方式
const router = new VueRouter({routes:[{path:'/login/:username/:password',component:login,name:"login"}]})
在地址栏输入参数,查看this.$route,查看属性
我们传递的参数通过 this.$route.params.key 拿到后面路径的参数
给路由传参数,可以直接在path后面追加
<router-link to="{path:'/login/admin/admin'}"></router-link>
通过 params进行传递
<router-link to="{name:'login',params:{username:admin,password:admin}}"></router-link>
小结
queryString的方式 通过 query属性拿到 key\valuerestFul 的方式 通过 params 属性拿到 key\value
(7) 嵌套路由
一个路由里面再有一个路由,就是在VueRouter配置规则的时候,一个路由规则对象除了 path、component、name,再由 child:[],放置子路由,里面再放一个路由规则对象
达成嵌套路由的形式
实现效果
注意
如何嵌套路由?
一个组件 users,代表用户列表,注册路由 /users
写一个组件 useradd ,代表增加用户的表单,这个组件注册一个路由 ,作为 /users的 嵌套路由
配置路由规则对象的时候,在users路由中 使用 children 数组属性,再放置 useradd 路由规则对象,没错就是套娃。
子路由中的path不能加 \,但是访问的时候,/users/useradd
const router = new VueRouter({routes:[{path:"",component: ,name:"",children:[ // 在children中注册嵌套路由{path:"",component: ,name:""}]}]})
同时子路由代表的组件只能在父路由进行使用,使用<router-view> 在 父组件的 template 的html代码中进行展示子路由组件展示在哪里。
使用 <router-link> 的to进行 绑定对象的话,一定要用vue语法,前面加:
路由传递参数通过超链接的方式,一种是a标签在路径后直接加参数,一种是<router-link> 的 to属性,使用对象中的 queryString、params(restful 风格)进行传递参数
<div id="app">{{msg }}<br><!-- 路由对应的组件展示的位置,用router-view 表示位置--><router-link :to="{name:'users'}">用户列表页</router-link><router-view></router-view></div><template id="users"><div><h3>用户列表</h3><!-- 引入 嵌套路由 useradd--><router-link :to="{name:'useradd'}">增加用户</router-link><table border="1" width="100%"><tr><th>id</th><th>name</th><th>age</th><th>salary</th><th>操作</th></tr><tr v-for="user in users"><th>{{user.id }}</th><th>{{user.name }}</th><th>{{user.age }}</th><th>{{user.salary }}</th><th><a href="">删除</a><router-link :to="{name:'useredit',query:{id:user.id,name:user.name,age:user.age,salary:user.salary}}">修改</router-link></th></tr></table><!-- 嵌套路由 useradd 在这里进行展示--><router-view></router-view></div></template><script>// 定义一个用户列表的组件const users = {template: `#users`,data() {return {users: []}},created() {this.users = [{id: 1, name: "xiaochen", age: 12, salary: 2300},{id: 2, name: "xsjkdas", age: 121, salary: 2500}]}}// 定义一个用户增加的组件,作为/users的嵌套路由 /users/addconst useradd = {template: `<div>name:<input type="text"><br>age:<input type="text"><br>salary:<input type="text"><br><button> 保存</button></div>`}// 定义一个用户增加的组件,作为/users的嵌套路由 /users/addconst useredit = {template: `<div>id:<input type="text" v-model="user.id" ><br>name:<input type="text" v-model="user.name"><br>age:<input type="text" v-model="user.age"><br>salary:<input type="text" v-model="user.salary"><br><button> 保存</button></div>`,data(){return {user:{id:"",name:"",age:"",salary: ""}}},created(){// 接收 超链接传递过来的 querythis.user.id = this.$route.query.id;this.user.name = this.$route.query.name;this.user.age = this.$route.query.age;this.user.salary = this.$route.salary;}}const router = new VueRouter({routes: [{path: '/users', name: 'users', component: users,children: [// 将用户增加作为嵌套路由进行配置路由// 嵌套子路由不能以 /开头,访问的时候 /users/useradd 才能成功{path: 'useradd', component: useradd, name: 'useradd'},{path: 'useredit',component: useredit,name: 'useredit'}]}// 将组件注册路由]});const a = new Vue({el: "#app",methods: {},data: {msg: "Vue 嵌套路由的使用!"},computed: {},router,//注册路由管理器对象created() {}})</script>
四、Vuex 状态管理器
VueX 的官方文档 /zh/
(1)简介
Vuex 是一个状态管理模式的库,集中存储所有组件的状态。
说到这里可能还有人不明白,什么叫做状态管理?
在之前我们见到父子组件传递参数的时候,使用prop进行声明接收,但是只能单向传递,父传给子,子组件要想改变参数的值无法影响到父组件以及其他组件的。
一个例子,有用户组件、员工组件、部门组件,在开发过程中,有一个数据count,三个组件中都要用到。
用户组件用到,父组件需要传递,员工组件用到,父组件传递,但是有一个很大的弊端,传递的数据只能单向流动,子组件要想修改count,没有办法影响全局。那么就会产生很大的问题
Vuex就是来放这些通用的数据与信息,并对其进行管理的仓库。使用Vuex任意一个组件对其进行修改都会全局
(2)在Vue Cli 中使用 Vuex
1、安装Vuex
默认安装的Vue-cli 是没有安装Vuex 的,需要我们下载导入
npm install vuex@3 --save
当前现在 Vue3成为了默认版本,vuex也更新到了 4版本,所以如果是vue2的话执行npm insatll vuex --save
安装的是4版本,很有可能出错。
版本匹配规则:
(1) Vue2 中要使用 vuex3 版本
(2) Vue3 中要使用 vuex4 版本
npm install vuex@3 --savenpm install vuex@4 --save
安装成功
2、配置 Vuex
在src中创建目录 stroe,创建js文件 index.js,仿照router中的index.js 导入vuex
注意点:最后new 的对象不是Vuex,而是Vuex.Store
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({// 属性})
在Vue的主入口处main.js 注册Vuex
import Vue from 'vue'import App from './App'import router from './router'import store from "./store"; // 导入 store ,导入vuex的对象Vue.config.productionTip = falsenew Vue({el: '#app',router,components: {App },template: '<App/>',store // 注册store 状态管理器})
(3)store 对象中的属性以及调用
1、state
相当于vue框架中的 data,专门存放数据的,这里的数据相当于全局数据,存放和定义共享的数据
export default new Vuex.Store({state:{count:1 // 定义一个全局共享的属性 count}})
state 的 使用
我们在组件中使用共享数据怎么使用呢?
this.$store.state.count
先通过 this.$store 拿到 vuex 的 store 状态管理器,拿到 state 属性,调用count 属性
2、multations
存放改变state数据的方法,相当于vue中的methods,组件通过调用multations中的方法来改变 state中的共享数据。
在multations中定义方法, 每个方法都有一个默认的参数,会将状态对象state传递给方法
export default new Vuex.Store({state: {count: 1},mutations:{// 存放修改共享数据 state属性的方法// 共享count++incrCount(state){state.count++;},// 共享count--decrCount(state){state.count--;}}})
组件如何调用?
在组件内部的属性methods中,在自定义的方法中使用调用方法的语句
this.$mit('方法名','传递的参数')
commit方法中第一个参数对应 store对象 multation的方法名,第二个参数是 组件传递的参数,但是如果传递多个参数,只能在第二个参数这里传递一个对象。
举例:
在组件中定义一个按钮,定义一个点击事件,修改共享数据count
index.js
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 1},mutations:{// 存放修改共享数据 state属性的方法// 共享count++incrCount(state,step){state.count+=step;},// 共享count--decrCount(state,step){state.count-=step;}}})
home.vue
<template><div><h1>{{this.$store.state.count}}</h1><button @click="incr">点击增加+10</button><button @click="decr">点击增加-10</button></div></template><script>export default {name: "Home",methods:{incr(){this.$mit("incrCount",10);},decr(){this.$mit("decrCount",10);}}}</script>
网页的效果展示
能够展示 store 对象 state 中的 count 属性,点击按钮能够完成对应的+10、-10的操作
3、getters
用来定义对共享数据一系列的计算方法,计算缓存,放置多次重复计算,与vue中的computed 作用一样。
举一个例子,在一个页面中我们需要多次展示 count*count 的数据,那么如果我们每次在对应位置都写 count * count 的话,那么会有很多重复性计算,所以为了方便使用,getters 属性记录计算的方法的返回结果,在组件中使用, 好处:只计算一次,缓存结果
getters:{// 计算count 的平方countSqrt(state){return state.count*state.count;}}
属性内部也是 定义方法,默认参数为 state 状态管理对象,返回计算的结果进行缓存
组件进行调用
this.$store.getters.countSqrt // 不是方法,作为属性调用
举例子
在首页展示两次 count*count 的数据,查看log的计算有多少次?
1、直接count*count计算
主页 Home.vue
<template><div><h1>{{countInit()}}</h1><h1>{{countInit()}}</h1></div></template><script>export default {name: "Home",data(){return{}},methods:{countInit(){console.log("============================");return this.$store.state.count*this.$store.state.count;}}}</script>
效果展示,调用了两次计算的方法
2、调用 getters 属性中的方法返回
index.js 定义 getters 中方法返回 count的平方
getters:{// 计算count 的平方countSqrt(state){console.log("===============");return state.count*state.count;}}
主页中Home.vue 进行调用
<template><div><h1>{{this.$store.getters.countSqrt}}</h1> <h1>{{this.$store.getters.countSqrt}}</h1></div></template>
效果展示,只调用了一次,第二次使用缓存数据