• 微信号
  • 微信号
您当前的位置:首页 > 学海无涯 > 茑语花香>vue2学习笔记vue2记录

vue2学习笔记vue2记录

孤峰 孤峰家 2023-08-08 160人阅读

vue基础知识 初识:

Vue实例跟容器是一对一的关系。

尝试2容器1vue实例 vue实例只能接管前面一个 后面一个容器管不了

<h1 id="title">nihao,{{name}}</h1> 

<h1 id="title">nihao,{{name}}</h1>

<script>new Vue({el:'#title',//尝试用了class 效果也是一样的 只照顾到前面那个data:{name:'北京'}

})

</script>

响应式原理 插值语法&模板语法

插值语法: {{js表达式}}

(js表达式可以理解成一个用变量去装的东西,a++,字符串拼接。。。)

插值里面的变量自动获得data对象里面的数据(其实是暴露VM模型的内部结构),data对象类似之前那个windows对象,属性为变量,里面再嵌套对象就按照对象:属性来调用。 模板语法:

通过vue命令改变标签的属性、行为等,用于解析标签。 数据绑定(v-bind、v-model)

简写:

v-bind 单向数据绑定 只能data–>容器

动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。

我的理解是:

v-bind就是动态地绑定dom元素的属性,让dom元素里面的属性的那个值跟表达式一样

eg:

v-bind: 将url当成一个变量 就去Vue实例里面找url属性了

可以简写成:

v-model 双向数据绑定 只能用在表单类元素(有value值的输入类元素)上

其实是对元素的value进行操作

<input class="inputbox" v-model:keywords="keywords" type="text" /> 

绑定class样式

补充数组操作

el&data的两种写法

可以使用v.$mount(‘css选择器’)来绑定对象

const v=new Vue({// el: ".title",//第一种写法data: {name: "北京",}, 

});

v.$mount('.title');//第二种写法

在写成普通函数声明的时候,函数的this指向vue实例,写成箭头函数的时候函数的this指向全局的window对象

MVVM模型

可以理解成dom是表示层 VueModel是逻辑层 Model是数据层。VM在页面dom元素设置监听,并且绑定数据层data中的数据,当data中数据更新时,将实时更新表示层dom,如果采用双向绑定,dom元素value改变数据层data中的数据也会实时改变。

补充:下面这样写会报Reference ERROR 说找不到alert属性 这是因为表示层dom绑死在VM上了,表示层只能看到VM作用域里面的数据 alert是window的 VM模型里面没有。。不是作用域链可以往外找这样。。可以将window作为内置对象解决(但是Vue实例是可以读到的window的属性的 那个是作用域链 要分清楚捏

数据代理

就是不直接操作对象,使用中间商操作数据 补充:Object.defineProperties(要修改的对象,属性,配置对象)

例子:obj2通过中间商x来操作obj对象

let obj={x:100} 

let obj2={y:200}

Object.defineProperty(obj2,'x',{get(){return obj.x//每次通过obj2访问obj.x都是通过getter去访问的},set(value){obj.x=value//每次通过obj2修改obj.x都是通过getter去访问的}

})

VM模型采用的也是数据代理,使用一个对象去new一个vue实例,数据层data中的数据**到vm模型里面,并进行加工之后使用_data属性存起来。使用数据代理,vm做中间商,好少写个_data。好像还用了观察者模式(?

事件处理

 <button id="root" v-on:click="show">nihao</button> 

const v = new Vue({data: {name: "北京",},methods: {//记住不要写成method了 有sshow:function() {console.log("hello");},}, 

});

v.$mount("#root");
事件修饰符

事件修饰符可以连用

点击事件

v-on:click

简写:v-on:简写成@

v-on:click===》@click 键盘事件

ctrl+y

计算属性

计算实例通过对Vue现有属性的计算得到新的属性,叫做计算属性。数据源改变,计算属性根据改变的数据源在原来数据的基础上进行修改。

我感觉跟数据代理很像,计算属性的数据源于Vue实例里面的data对象里面的值,双向绑定的。数据源改变,计算属性调用getter更新,注意,不更新绑定的数据就没什么用,不更新数据源计算属性不会变(其实跟页面元素很像耶。。不过计算属性也的的确确是Vue、VC实例里面的属性就是说。

不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值

这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

computed: {now: function () {return Date.now()} 

}

缓存这两个字很重要,缓存意味着是计算属性先保留了一份数据源的值,等到响应式依赖数据源发生变化的时候才会更新计算属性数据源。

methods的this是整个Vue实例,不加this就找不到的原因已经是不在methods这个对象里面,找上一层一直找到最外层的window也没有(作用域链想起没哇(。 以前的知识不要丢哇

<div id="root">姓 <input type="text" v-model='fn'></br>名<input type="text" v-model='sn'></br> 

full<span>{{full()}}</span>

</div>

new Vue({el:'#root',data:{fn:'fn',sn:'sn'},methods:{full(){return this.fn+'-'+this.sn//为什么要加this才能用 不加this会报错//[Vue warn]: Error in render: "ReferenceError: fn is not defined"}}})
</script>

在最外面加了就能过了

fn=2 

sn=1

new Vue({el:'#root',data:{fn:'fn',sn:'sn'},methods:{full(){return fn+'-'+sn}}

})

姓名例子:

let vm=new Vue({el:'#root',data:{fn:'fn',sn:'sn'},computed:{full:{get(){console.log('getter');return this.fn+'-'+this.sn},set(value){const arr=value.split('-')this.fn=arr[0]this.sn=arr[1] }}} 

})
计算属性简写(只读不改):

计算属性setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter: // ...

computed: {fullName: {// getterget: function () {return this.firstName + ' ' + this.lastName},// setterset: function (newValue) {var names = newValue.split(' ')this.firstName = names[0]this.lastName = names[names.length - 1]}}

}

// ...

现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。

计算属性setter是会更改数据源的。 监视属性 Watch

监视的属性不存在监视没有作用 但是不会报错(f u

watch:{keyWord:{immediate:true,handler(value)//value传的是监控的值的新值,第二个变量传的是之前的值{this.filPer=this.per.filter((p)=>{//vue管理的函数this应该是vue实例return p.id.indexOf(value)!==-1})}} 

}
深度监视 deep

监视引用变量的时候,watch默认检测的变量存的地址值,只要对象不变,watch是不会检测到变化的,可开启deep值,检测引用的对象的变化。

例子:

点击btn,obj的bool置反。watch监视的是对象obj,开了deep,能监视到对象里面的改变,但是由于监视的对象没变,所以传给handler的newValue跟oldValue都没有变化,打印的bool值就都是较新那个值啦。

 <div id="root"><button @click="sw">{{obj.bool}}</button></div> 

new Vue({el:"#root",data:{obj:{bool:true}},methods:{sw(){this.obj.bool=!this.obj.bool// this.obj={}}},watch:{obj:{deep:true,handler(newValue,oldValue){console.log(newValue.bool+','+oldValue.bool)}}} 
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ebo4jka-1647068009438)(D:/Typora/image-20211025201456438.png)] 监视简写(只使用handler):

那个function别写成箭头函数了,会出this问题(。

Vue原生的数据监视原理

使用观察者模式

Vue.set()

this

补充箭头函数this

要知道js里面只有两种作用域(es5):函数作用域跟全局作用域。es6新增的作用域是对于let关键字而言的,对于其他还是只有两种作用域啦。

箭头函数本质是return语句啦,没有自己的this,所以用的定义时父级的this

如例子中 作用域只有一个:全局window 对象a并不是作用域哦!对象没有自己的作用域,所以不能充当箭头函数的this,套一个普通函数,里面再放箭头函数,移花接木一下估计可以。

var name = 'window'; var A = {name: 'A',sayHello: () => {console.log(this.name)} 

}A.sayHello();// 还是以为输出A ? 错啦,其实输出的是window

移花接木ver

var A = {name: 'A',sayHello:function (){let a=()=> {console.log(this.name)}a()} 

}A.sayHello();//A

普通函数的this可以指向A 是因为自己分割出了一个作用域

var name = 'window'; // 其实是window.name = 'window'var A = {name: 'A',sayHello: function(){console.log(this.name)} 

}A.sayHello();// 输出A
条件渲染(v-if、v-show)

v-show(操作css)

底层通过调整css的display v-show='false’是 元素节点还是在的只不显示了。

<div v-show="false" id="root" ><button @click="sw">{{obj.bool}}</button> 

</div>

v-if(操作dom)

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

条件判断语句,v-if条件为真时才渲染元素,条件为假时是不渲染元素的,所以节点根本就不在dom树里面。

<div v-show="false" id="root" ><button @click="sw">{{obj.bool}}</button> 

</div>

还有v-else-if v-else跟普通的一样 就是形成一组判断了就是说 btw v-else后面跟条件没有用(但是也不会报错就是说

为了形成一组判断 不可以被打断 被打断后的就判断作废 被没有相通的v-if

<div id="root" ><div v-if="false"></div><button @click="sw">{{obj.bool}}</button><div v-else-if='true'>11111111</div> 

</div>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RtFv9Tzi-1647068009443)(D:/Typora/image-20211026184032244.png)]

v-if 例子2

window.onload = function () {//创建一个vue实例var app = new Vue({el: "#app",data: {type: "A",loginType: "username",},methods: {changeloginType() {let self = this;if (self.loginType == "username") {self.loginType = "";} else {self.loginType = "username";}},},}); 

style="color: green"
>v-if的弹框切换</div><template v-if="loginType === 'username'"><label>用户名:</label><input placeholder="Enter your username" key="username-input" /></template><template v-else><label>密码:</label><input placeholder="Enter your e**il address" key="e**il-input" /></template><button @click="changeloginType">切换状态</button> </div> 针对例子补充 template标签:

浏览器不对template进行渲染 渲染时自动丢掉 不会出现在dom节点里面 只能和v-if配合使用 v-show不行

<div><div id="root"><template><div v-if="false"></div><button @click="sw">{{obj.bool}}</button><div>11111111</div></template></div> 

</div>

而且会导致找不到root 不是外面包东西的原因 好像就是因为template

<div><template><div id="root"><div v-show="false"></div><button @click="sw">{{obj.bool}}</button><div>11111111</div></div></template> 

</div>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sqyf0ekB-1647068009444)(D:/Typora/image-20211026184944175.png)] 列表渲染(v-for) 基本概念

当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。(但是文档并不推荐两个一起用!)

基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression,为当前遍历的元素提供别名

首先要明确,v-for写在哪里就是列表渲染哪个,如下面。v-for写在div里面,渲染items.length个div!!!

v-for别名的作用域是自己跟子元素。

<div v-for="item in items"><!--item就是别名-->{{ item.text }} 

</div>

另外也可以为数组索引指定别名 (或者用于对象的键): <div v-for="(item, index) in items"></div>

<div v-for="(val, key) in object"></div>

<div v-for="(val, name, index) in object"></div>

v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示(绑定的key就变成数组元素的索引了)(有看到说key不止这种用法)

以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute(文档原文)

<div v-for="item in items" :key="item.id">{{ item.text }} 

</div>
key注意点:

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升(有key性能会好一点?)

不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。

v-for就是做循环,就是包装了for循环

v-for可以连着in跟of一起(即支持for..in、for...of) v-for…in遍历数组

<div id="root"><ul><li v-for="p,index in person">{{p}},{{index}}</li></ul> 

</div>

new Vue({el: "#root",data: {person:[{id:001,name:1},{id:002,name:2},{id:003,name:3},]}, 
});

v-for…in遍历对象

第一个参数是属性的值,第二个参数是属性名,第三个是index,属性排第几个(只有对象可以这么搞,数组不行,数组第二个一定是index)

<div id="root"><ul><li v-for="(value,attr,index) in person">{{value}}---{{attr}}---{{index}}</li></ul> 

</div>
new Vue({el: "#root",data: {person:{id:"dsasf",name:"sdgvsdf"},}, 
});

使用v-for…of遍历数组、对象、次数、字符串(后两个基本不用)

遍历次数跟python的for in range一样。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yAteWrSX-1647068009452)(D:/Typora/image-20211026190235388.png)] v-for注意点

在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。

<ul> <li v-for="item in items"><li>{{items}}</li> </li></ul> <ul> <li></li><li>{{items}}</li> </ul>

由于兄弟是看不见的 所以不能看到那个items 也就出错了

v-for是先做循环 然后再跟着下面的(其实这个就是很普通的一个点,就是要记住v-for就是for就是经过包装的for 可以用来控制虚拟dom节点

<li @mouseenter="changeLiBgc(index)"v-for="(groupMenuitem, index) in groupMenuitems" 

:key="index"

:class="{ cur: currentIndex == index }"></li>

changeLiBgc(index) {this.$data.currentIndex = index;console.log("index"+index)console.log(this.$data.currentIndex)},

这个是在写尚品汇的时候的一个小的li标签,是三级联动部分。

当鼠标移动到li上的时候触发mouseenter事件,函数changeLiBgc(index)执行,传的是li执行v-for的索引,只会传鼠标enter的那个元素的index。按照这个的话,后面就比较好理解,但是我自己说不出个所以然来。(是不是因为mouseenter,传EventTarget传了li的index)

我觉得可能不能完全按照以前的for循环去理解v-for,我以前学的for循环做完就不会再进行改变了,但是v-for是动态的。

=》v-for做完循环,将虚拟dom变成真实dom,它就会有各种各样的属性,渲染出来的li对象里面有自己的index,当鼠标放上去的时候触发mouseenter事件,将currentIndex赋值成index,然后classv-bind绑定了,计算{}里面js表达式的值。

key原理 diff

在内存中对key相同的节点进行比较,如果内容一样则将之前渲染过的节点直接拿来用,否则就将放弃掉之前的节点,重新渲染虚拟dom节点成真实dom节点。 总结:

就是使用index作为key的时候(不写key默认将遍历时候的index作为唯一标识),当在前面插入/删除节点时,会造成节点与index的顺序改变 从而造成输入类元素对应不上

如果自定义唯一标识的话,就可以进行更多的重用 只新增新的节点 省去了重新生成旧节点 效率更高

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xr6IwQ4-1647068009454)(D:/Typora/image-20211026222826520.png)]

补一个用index做key的坏处:

列表过滤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ufJExOV-1647068009459)(D:/Typora/image-20211027201206101.png)]

new Vue({el:'#root',data:{keyWord:'',per:[{id:'001',name:'aa'},{id:'002',name:'bb'},{id:'003',name:'cc'},],filPer:[]},watch:{keyWord:{immediate:true,handler(value){this.filPer=this.per.filter((p)=>{return p.id.indexOf(value)!==-1})}}} 

})

补充数组filter

Array.filter(),不会对空数组进行检测,不会改变原始数组。

Array.filter(()=>{return 判断条件//这个函数的返回值要是布尔值 要么true 要么false 

})//filter返回由旧数组符合条件的值的数构成的新数组
表单收集数据的技巧

其他指令 v-html

v-cloak

防止网速过慢出现插值语法。。

自定义指令

全局指令和局部指令的区别:

全局指令可供整个页面使用,而局部指令只作用于他定义的那个vue实例

全局指令就是直接定义在Vue上,局部就是包在一个vue实例里面 函数式声明

自己敲了一遍 修改name已经不会调用big了(不知道是不是vue3的优化?

调用big应该修改成:

1.第一次解析模板时 被调用

2.指令其绑定的数据源发生改变

const vm=new Vue({el: "#root",data: {n: 1,name:"shang"},directives: {big(el, binding)//第一个传的是要操作htmlElement元素 第二个传的是这个绑定的对象{console.log('big')el.innerText=binding.value*10},}, 

});

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YOyWisMA-1647068009466)(D:/Typora/image-20211028132122785.png)]

输出的binding:

对象式声明

官方文档的使用函数式获取不了焦点是因为一开始在vue执行指令的时还没有放到页面上 所以element.focus没有用

上面简写的函数式声明,只用了bind、update,没有inserted。自定义指令里面函数的this都是window,并不是vue去维护指令的。其实也好理解,因为自定义指令是直接对dom操作,不经vue手也很正常。

Vue.config.productionTip = false; 

const vm=new Vue({el: "#root",data: {n: 1,name:"shang"},directives: {big(el, binding) {console.log(this)//windowel.innerText=binding.value*10},fbind:{//指令与元素成功绑定时(元素还在内存 vue还没有将元素放到页面上 简写成函数式的话就是只用bind+update了bind(el,binding){el.value=binding.valueconsole.log(this)//window},//指令所在元素**入到页面时inserted(el,binding){el.focus()},//指令所在模板被重新解析时(模板重新解析?update(el,binding){console.log('update')}}}

});
全局指令

写在vue实例里面的是局部指令 只能那个vue实例用 其他实例用不了 写全局指令的话要放到Vue里面(写到构造函数里面 当成属性一起继承使用 生命周期

生命周期图详解:

beforeCreate:初始化生命周期、事件(mothods)但是还没执行数据代理(没有_data _data是undefined!beforeCreate的before是指在数据检测、数据代理之前

created:初始化数据检测、数据代理

然后开始找el、template编译虚拟dom

beforeMount:对dom的操作最终不奏效

在挂载之前,将虚拟dom编译,产生el用el 用el用el替换掉el

将真实dom挂载到页面上

Mounted:东西都挂好了,页面上显示的是经过vue编译、解析的dom元素 可以对页面上的元素做点想做的操作了。

beforeUpdate:在内存中 已经更新了数据 但是页面上的数据还没更新 还没将更新的元素解析挂到页面上

updated:数据已经更新到页面了 页面数据与内存数据同步

beforeDestroy:可以读到data、method,但是不能够进行修改 因为更新要进行update 已经走到这里了 不能回头走update了

destoryed

摧毁阶段 断掉事件监听、数据检测、跟其他实例的联系 虽然说断掉了事件监听 但是已经绑上的dom事件不会随着vue事件被摧毁而解开 比如给btn绑了点击事件 vue实例destoryed了btn的点击事件还是绑着的

生命周期函数mounted(挂载)

页加载渲染完成之后,会自动执行的方法。

Vue完成模板解析,并将真实dom放到页面(挂载)之后执行,只会执行一次。

Vue.createApp({data() {return {counter: 1,};},mounted(){console.log("页面加载完成之后自动执行的函数")setInterval(()=>{this.counter+=1},1000)},template: "<div>{{counter}}</div>", 

}).mount("#app");
<div id="root">姓 <input type="text" v-model='fn'></br>名<input type="text" v-model='sn'></br>full<span>{{full}}</span> 
</div>
组件

模块化跟组件化是两种并行的思想。模块化跟组件化都是封装,就是封装内部逻辑,暴露一些接口。 data要用函数式:

对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题

Vue.config.productionTip = false; 

//组件

const school = Vue.extend({template: `<div>{{names}}<br>{{address}}</div>`,data() {return {names: "dsgfd",address: "gz",};},

});

//反正只是一个配置对象 自动有个判断 其实也调用了 Vue.extend

const school = {template: `<div>{{names}}<br>{{address}}</div>`,data() {return {names: "dsgfd",address: "gz",};},

}new Vue({el: "#root",components: {//配置项都是对象 要写对 真无语了 我是笨蛋schools: school,},

});
VueComponent

在写props代码的时候一直没有注册 然后就提示没有使用子组件 原来是因为没有注册 人家不认识 就说没有用!!!

Vue.config.productionTip = false; 

//组件

const school = Vue.extend({//在调用Vue.extend()的时候其实自动new VueComponent()来构造组件了template: `<div>{{names}}<br>{{address}}</div>`,data() {return {names: "dsgfd",address: "gz",};},

})new Vue({el: "#root",components: {//一定要注册 注册才算使用了 不登记谁tm知道你名字 人家不认识啊schools: school,},

});

console.log(school)

vc跟vm差不多 belike vm删减版

vm-》app(vc头子)-》其他vc 还是子父节点那套

Vc&vm的原型链

VueComponent.prototpye.__proto__=Vue.prototpye

脚手架

render函数
//简写 

new Vue({render: h => h(App),

}).$mount('#app')

//完整版

new Vue({render(createElement) {return createElement(App)},

}).$mount('#app')

render(createElement)

渲染函数,根据拿到的虚拟节点渲染到页面上。一定要有返回值,用createElement返回,要拿到节点才能去渲染。

createElement(html元素|组件,元素属性,子节点内容)用于创建虚拟dom元素。约定的简写叫 h, vm中有一个方法 _c, 也是这个函数的别名。在Vue2中,虚拟DOM就是通过一种VNode类表达,每个DOM元素或组件都对应一个VNode对象。

ref

相当于原生的getElementById()

app.vue文件函数里面的this都是vc组件 确实(。不然呢

show(){console.log(this)}

show(){console.log(this.$refs.btn)}

给html标签加上ref属性之后,就自动加到vc的$refs里面,被收集了。跟以前加id是一样的。

如果加的是组件标签就将组件加到$refs里面

props

首先要明确 props传的东西只是变量里面的值(也就是belike浅**) 传的只是对象的地址 并不是对象的值(props是只读的)

首先可以实现组件间通信,主要是父子间的通信,实现兄弟间的通信就比较麻烦,要借助父组件,子传父再传兄弟,不如直接使用vuex比较方便。

为什么说是父子组件间通信呢,这主要是通过给组件的属性赋值来传递。要注册组件这必然是父子组件了。父传子:

//home.vue 

<div><three :i**ove="true"></three></div>

此外,从子->父的通信 父给子一个函数子调用,传参,数据传回父组件里面。

除了上面的通过props来静态地绑定,也可以通过v-bind动态绑定。

prop 可以通过 v-bind 动态赋值,例如:

<!-- 动态赋予一个变量的值 --> 

<blog-post v-bind:title="post.title"></blog-post><!-- 动态赋予一个复杂表达式的值 -->

<blog-postv-bind:title="post.title + ' by ' + post.author.name"

></blog-post>
传入一个对象的所有 property

如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:

post: {id: 1,title: 'My Journey with Vue' 

}
<blog-post v-bind="post"></blog-post>

等价于:

<blog-postv-bind:id="post.id"v-bind:title="post.title" 

></blog-post>
改变一个prop的方法(2种):

**这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。**在这种情况下,较好定义一个本地的 data property 并将这个 prop 用作其初始值:

props: ['initialCounter'], 

data: function () {return {counter: this.initialCounter}

}

**这个 prop 以一种原始的值传入且需要进行转换。**在这种情况下,较好使用这个 prop 的值来定义一个计算属性:

props: ['size'], 

computed: {nor**lizedSize: function () {return this.size.trim().toLowerCase()}

}
注意

在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身****将会影响到父组件的状态。 mixin

mixin的话this是指向组件的 纯纯滴工具人

//组件 

<template>

<div>

<h1>子组件</h1><button @click="showname">showname</button>

</div>

</template><script>

import {mixin} from './mixin'

export default {name:'child',props:{zsq:{type:String,default:'zzzsq'}},methods: {showzsq(){console.log(this.zsq)}},data(){return {name:'jack'}},mixins:[mixin]//配置项一定是数组 一个也是

}

</script>
//mixin.js 
export let mixin={methods:{showname(){console.log(this.name)}}}
插件

scoped

在vue单文件组件中,为了防止全局同css类名名样式的污染,vue-loade对单文件组件 <style> 标签增加了scoped属性的处理。原理就是在html标签上添加data-v-xxxxxxxx属性,然后在css类名后添加属性选择器,即利用css类选择 + 属性选择器实现样式局部化。

使用了scoped之后,就加了data-v-xxxxxxxx属性属性而已,避免污染其他的。

todolist总结

本地存储

以键值对的形式保存,只能够保存字符串,对象用json.stringify转成字符串再保存,不然会就直接调用tostring方法没啥意义

sessionStorage是会话存储,打开一次浏览器算是一次会话,关闭浏览器就没有了。

LocalStorage清除:1.调用clear/removeStorage 2.浏览器设置里面清除缓存

组件自定义事件 绑定自定义事件:

有两种调用:

1.通过$emit

sname是自定义事件名 当事件触发是调用**函数

App.vue

<template><student @sname="**"></student> 

</template>

student.vue

<template><div><span>{{ studentName }}</span><button @click="send**">获取学生姓名</button></div> 

</template><script>

export default {name: "student",data() {return {studentName: "李华",};},methods: {send**() {this.$emit('sname',this.studentName);//调用函数 $emit触发sname事件,后面就是给sname传的参,可以传无限多个},},

};

</script>

2.ref

<script> 

export default {name: 'App',components: {school:school,student:student},methods: {**(sn){console.log(sn)}},mounted() {this.$refs.student.$on("sname",this.**)//this.refs.student拿到了App上的student子组件 然后通过$on给子组件绑定自定义事件sname,sname触发时调用**函数

//这里有一个坑 当使用methods里面声明的函数,函数的this一定是methods的那个vue对象

//如果这里写成 这样虽然可以输出 但是app实际上是没有拿到sn的 因为下面这个函数的this指向的是student子组件

//回调函数也是普通的函数,js里面就函数跟对象可以切割作用域。

//回调函数有自己的this 里面保存的就是调用回调函数的对象=》谁调用,回调函数的this就是谁this.$refs.student.$on("sname",function(sn){console.log(sn)this.sname=snconsole.log(this)})//改成箭头函数就行 //箭头没有自己的作用域,没有自己的this 所以用mounted的作用域(?用的就是当前组件的作用域,即Appthis.$refs.student.$on("sname",(sn)=>{console.log(sn)this.sname=snconsole.log(this)})},

}

</script>

要加native才会当成原生 默认是自定义事件

解绑:

全局事件总线

能够实现任意组件间通信

我的理解就是在用一个所有人都能看到的中介,也有点像计网里面的总线结构。所有人都在总线(中介)里面做一个自定义事件,a要给b传数据就调用触发b的自定义事件。其实用的也是昨天学的使用自定义事件来实现子传父的那一套。

为了让所有人都能够看见中介使用直接在Vue里面定义。

beforeCreate()这时候还没有初始化完,所以可以在这里放个prototype,来让实例继承$bus。

补充$on:

this.$bus.$on("checkTodo",this.checkTodo) 消息订阅与发布

订阅者:

mounted(){pubsub.subscribe('hello',function(msgName,data){console.log('hellllo订阅'+msgName+" "+data)console.log(this)//undefined//使用第三方库的话,普通函数的this就是undefined 毕竟第三方库vue也不知道你用的什么//使用箭头函数就可以跳出调用的 直接出去找this 就是这个vc实例了 

})

发布者:

methods: {send**() {pubsub.publish('hello','6666666666')//消息名 数据//传的时候传的第一个参数是消息名,第二个参数才是数据..//就是回调函数收到第一个参数是消息名,第二个才是数据 //改todo案例的时候给我整无语了 一直删不掉 才知道参数收的消息名}, 

},

取消订阅:

todo发布:

 del(id) {this.$bus.$emit("delTodo", id);// pubsub.publish('delTodo',id,'xx');}, 

delTodo(id){//这个参数是消息名 谁狠狠无语了。。this.todos=this.todos.filter( (todo) =>{return todo.id!=id}) nextTick

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

补充Vue的异步更新队列

Vue的更新DOM是异步的。数据变化(比如vm.someData = 'new value'),Vue不会立即重新渲染组件,执行DOM的更新。而是把这些要更新的事件放入一个队列里面,并进行去重。在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。

当你设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。这样回调函数将在 DOM 更新完成后被调用。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)

<div id="example">{{message}}</div> 

var vm = new Vue({el: '#example',data: {message: '123'} 

})

vm.message = 'new message' // 更改数据

vm.$el.textContent === 'new message' // false

Vue.nextTick(function () {vm.$el.textContent === 'new message' // true

})

组件内使用:

回调函数中的 this 将自动绑定到当前的 Vue 实例上:

<script> 

Vue.component('example', {template: '<span>{{ message }}</span>',data: function () {return {message: '未更新'}},methods: {updateMessage: function () {this.message = '已更新'console.log(this.$el.textContent) // => '未更新'this.$nextTick(function () {//这里的this是vcconsole.log(this.$el.textContent) // => '已更新'})}}

})

</script>

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await语法完成相同的事情: methods: {updateMessage: async function () {this.message = '已更新'console.log(this.$el.textContent) // => '未更新'await this.$nextTick()console.log(this.$el.textContent) // => '已更新'}

}

总结?

这个是在尚硅谷那个项目里面看到的 顺便看了一下vue的响应式原理 才知道vue的更新是异步的

在组件里发请求,我们希望的是等到返回的数据,然后对数据执行v-for,但是由于这个vue对dom更新是异步的。可能由于返回太久,先对没有返回的的数据执行v-for,执行dom更新,对于后面返回的数据无动于衷。使用this.$nextTick的话就可以把操作排到队伍较后面,等到异步完成了再上。 动画

下面这几种才能用vue的动画

条件渲染 (使用 v-if)

条件展示 (使用 v-show)

动态组件

组件根节点

vue的动画用的是transition 的封装组件,就是什么要加上动画效果,就用<transition><\transition>包起来。

如果有多个组件执行动画:

用v-for然后用<transition-group><\transition-group>包起来,而且要执行key

用div包起来,这样就是还是一个节点

下例(过渡、动画帧):

过渡例子:

<div id="**"><button v-on:click="show = !show">Toggle</button><transition name="fade"><p v-if="show">hello</p></transition> 

</div>
.fade-enter-active, .fade-leave-active {transition: opacity .5s; 

}

.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {opacity: 0;

}

动画帧例子:

<div id="example-2"><button @click="show = !show">Toggle show</button><transition name="bounce"><p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p></transition> 

</div>

.bounce-enter-active {ani**tion: bounce-in .5s; 

}

.bounce-leave-active {ani**tion: bounce-in .5s reverse;

}

@keyframes bounce-in {0% {transform: scale(0);}50% {transform: scale(1.5);}百% {transform: scale(1);}

}

当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:

自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。

如果过渡组件提供了 JavaScript 钩子函数(before-enter,enter,after-enter,enter-cancelled,before-leave,leave,after-leave,leave-cancelled),这些钩子函数将在恰当的时机被调用。

(当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。)

如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同) 过渡的类名

在进入/离开的过渡中,会有 6 个 class 切换。

v-enter:定义进入过渡的开始状态。在元素**入之前生效,在元素**入之后的下一帧移除。(我感觉就是插入的那一帧?)

v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素**入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。

v-enter-to:定义进入过渡的结束状态。在元素**入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。

v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。

v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。

v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。 css动画补充: @keyframes(关键帧)

关键帧 @keyframes at-rule 规则通过在动画序列中定义关键帧(或waypoints)的样式来控制CSS动画序列中的中间步骤。

@keyframes slidein {from {transform: translateX(0%); }to {transform: translateX(百%);} 

}

(mdn)要使用关键帧, 先创建一个带名称的 @keyframes 规则,以便后续使用 ani**tion-name性将动画同其关键帧声明匹配。每个 @keyframes 规则包含多个关键帧,也就是一段样式块语句,每个关键帧有一个百分比值作为名称,代表在动画进行中,在哪个阶段触发这个帧所包含的样式。也可以按任意顺序列出关键帧百分比;它们将按照其应该发生的顺序来处理。

(菜鸟教程)创建动画是通过逐步改变从一个CSS样式设定到另一个。

在动画过程中,您可以更改CSS样式的设定多次。

指定的变化时发生时使用%,或关键字"from"和"to",这是和0%到100%相同。

0%是开头动画,100%是当动画完成。

感觉有点像进度条,from是开始0%处,干什么,然后中间20%、30%干什么,较后是到to干什么。逐渐从0%相似到百%相似。 重复定义

如果关键帧重名的话,以较后一次定义的为准。一个动画在一个时间只会用一个关键帧。一个关键帧(@keyframes)里面有多个一样的百分比,比如有两个20%,就将这两个20%的样式重叠。 配置代理(解决跨域问题)

为了解决跨域问题可以配置一个代理服务器

8080端口跟8080代理服务器的话就不算跨域,代理服务器跟真的要传数据的服务器之间也没什么跨域问题(跨域是ajax

浏览器的一个保护措施

这个public就是8080代理服务器的根目录 如果使用第一种方式的话,在里面找到就直接用自己的,就不进行转发了。

一定要写pathRewrite,不然url就会带api,在后端服务器中根本没这个路径,or拿错(。 插槽 默认插槽

在<slot> <\slot>的位置插入自定义标签的

app.vue

catagory.vue

具名插槽

允许在自定义标签里面放多个标签 为slot指定名字 然后再放进去

↓已废弃

这种是现在推荐的v-slot写法:但是只支持template标签

作用域插槽

通过给子组件里面的slot插槽绑定数据来传数据给父组件 slot-scope 废弃

推荐 2.6.0 新增的 v-slot。

预期:function argument expression

用法

用于将元素或组件表示为作用域插槽。attribute 的值应该是可以出现在函数签名的参数位置的合法的 JavaScript 表达式。这意味着在支持的环境中,你还可以在表达式中使用 ES2015 解构。它在 2.5.0+ 中替代了 scope。

此 attribute 不支持动态绑定。

参考:作用域插槽 scope 移除

被 2.5.0 新增的 slot-scope 取代。推荐 2.6.0 新增的 v-slot。

用于表示一个作为带作用域的插槽的 <template> 元素,它在 2.5.0+ 中被 slot-scope 替代。

用法:

除了 scope 只可以用于 <template> 元素,其它和 slot-scope 都相同。

使用案例:

总结

Vue-x 概念

专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中的多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且适用于任意组件间通信。

集中式:把所有人集中在一起上课,上课只需要上一遍。

分布式:到每个人的家里面,给每一个人都上一遍课。 适用场景(多个组件要共享统一份数据)

多个视图依赖同一状态

来自不同视图的行为需要变更同一状态。 工作原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9d4ro2yr-1647068009518)(D:/Typora/20220105180904.png)]

脚手架import机制:

先全局扫描一遍,将import的文件先执行一次

store/index.js

**in.js

// 这个文件用于准备Vuex的核心storeimport Vue from 'vue' 

import Vuex from 'vuex'

// actions响应组件中的动作

const actions={// 这里context上下文就是那种的ministore 传两个值 一个ministore一个是valueplus:function(context,value){console.log("actions",context)// 这样做的就是一个转发 context.commit("plus",value)}// plus:function(context,value){// console.log("actions")// }

}

// mutations用于操作数据(state)

const mutations={// this.sum++plus:function(state,value){// console.log(state,value)state.sum++console.log(state,value)// console.log("mutations")}

}

// state储存数据

const state={sum:0

}

// Vue.use(Vuex)

export default new Vuex.Store({actions,mutations,state

})

state

__ob__: Observer这些数据是vue这个框架对数据设置的监控器,一般都是不可枚举的。

网上有很多解决的方案:

第一种:__ob__: Observer 是 Vue 对数据监控添加的属性,如果想去掉可以用赋值的方式。例如Object.assign({},this.owner)。 用这种方式也是可以解决。

**第二种:**假设list里面存放的就是那些带有__ob__: Observer的可以用JSON.parse(JSON.stringify(this.list))完美解决

完整案例:

score/index.js

// 这个文件用于准备Vuex的核心storeimport Vue from 'vue' 

import Vuex from 'vuex'

// actions响应组件中的动作

const actions={// 这里context上下文就是那种的ministore 传两个值 一个ministore一个是valueplus:function(context,value){// 这样做的就是一个转发 context.commit("plus",value)},oddplus:function(context,value){if(this.state.sum%2){// 这样做的就是一个转发 context.commit("plus",value)}}

}

// mutations用于操作数据(state)

const mutations={// this.sum++plus:function(state,value){// console.log(state,value)state.sum++console.log(state,value)// console.log("mutations")}

}

// state储存数据

const state={sum:0

}

// Vue.use(Vuex)

export default new Vuex.Store({actions,mutations,state

})

count.vue

<template> 

<div><span>计算结果:{{$store.state.sum}}</span><button @click="plus">+1</button><button @click="oddplus">奇数+1</button>

</div>

</template><script>

export default {name:"count",data() {return {// sum:0,value:0}},methods: {plus(){this.$store.dispatch('plus',2)// console.log(this.$store)},oddplus(){this.$store.dispatch('oddplus',2)}},

}

</script><style></style>
<template><div id="app"><count></count></div> 

</template><script>

import count from './components/count'export default {name: 'App',components: {count}

}

</script><style>

#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-**oothing: antialiased;-moz-osx-font-**oothing: grayscale;text-align: center;color: #2c3e50;**rgin-top: 60px;

}

</style>
actions muation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

mutation 必须是同步函数。

mutations: {someMutation (state) {api.callAsyncMethod(() => {state.count++})} 

}

devtools需要记录mutation。然后如果mutation里面的函数是异步的话,不能控制异步函数什么时候做回调,也追踪不了回调函数里面的状态的改变,所以devtools根本就记录不了mutation了。 state

vuex使用单一状态树,用一个对象就包含了全部的应用层级状态,作为一个“唯一数据源 (SSOT)”而存在。整个应用只有一个store实例。

state作为构造器选项,定义了所有我们需要的基本状态参数。 getters

**p(4个)

记得要在vuex里面进行引入

**pState

就是从state里面取出属性来当计算属性的

数组写法:

computed:{//意思是将vuex中的city数据映射到组件的computed属性里...**pState(["city"]) 

}

对象写法:

意思是将store里面的state里面的city属性映射到computed属性中的currentCity中(**p本身就有映射的意思)。即currentCity代表了$store.state.city

computed:{...**pState({currentCity:"city"})} 

computed: **pState({// 第一种写法count: 'count', // 第二种写法**: (state) => state.**,// 用普通函数this指向vc组件,要注意 from: function (state) { return this.str + ':' + state.from},// 注意下面的写法看起来和上面相同,事实上箭头函数的this指针并没有指向vue实例(this是undefined 应该是es6用的严格模式 所以顶层的this是undefined的原因),因此不要滥用箭头函数from: (state) => this.str + ':' + state.frommyCmpted: function () {// 这里不需要state,测试一下computed的原有用法return '测试' + this.str}}),

写成函数的都会在用那个属性的时候 函数会调用一下 我感觉是计算属性的原因 **pGetters

**pMutations

<button @click="increment">+1</button>

我传的是pointerevent

**pActions

小总结

其实就是跟谁交流就**p谁 **p其实还有一个映射的意思捏

模块化编码

分块暴露

里面记得写一个namespaced用以区分 让外面的人认识它!!注意是namespaced

路由 基本概念

通过切换页面内的部分组件 实现单页面部分内容(组件)的一个切换

使用方法(Vue2)

路由是vue的一个插件 app.use(router)

路由配置:

router/index.js

import VueRouter from 'vue-router'import change from '../pages/change' 

import home from '../pages/home'

import next from '../pages/next'//这里就是路由配置

const router=new VueRouter({//这里写的就是路由规则routes:[{path:'/change',component:change},{path:'/home',// name:'home',component:home,//嵌套了多级路由children:[{path:'next',component:next,}]}]

})export default routerconst originalPush = VueRouter.prototype.push

VueRouter.prototype.push = function push (location) {return originalPush.call(this, location).catch(err => err)

}

模板 router-link

这个是放url来进行跳转的,放在模板里面 较后经过vue-router库的编译会变成a标签。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL。

active-class 点击激活里面配置的css样式

一级路由的写法:

多级路由:

router-view

这个用于指定组件的呈现位置。放在那里就是哪块组件进行变化。

路由注意点

$router、$route

1.文档

通过调用 app.use(router),我们可以在任意组件中以 this.$router 的形式访问它,并且以 this.$route 的形式访问当前路由。

所以可以this.router是全局的路由,每一个组件都能访问到它,this.router是全局的路由,每一个组件都能访问到它,this.router是全局的路由,每一个组件都能访问到它,this.route是当前组件的路由。

我的理解:

$router:全局路由的实例,是router构造方法的实例,用于编程式路由导航进行的路由跳转

$route:当前的路由信息对象

$router里面有全局的路由什么的 还有history、mode什么的,而且还能看到路由规则

route我理解成当前的路由对象(也不是页面,就是当前的路由对象)

2.注册完路由组件之后,不管是路由、路由组件、非路由组件上都有$router、$route属性

两者之间的联系this. router中的currentRoute(其实就是当前路由、、)就是组件路由的this.route

ajax相关参数 路由的query参数

跳转路由并携带query参数 to的字符串写法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eryYzsk3-1647068009545)(D:/Typora/image-20220111231355329.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iu14Ohn2-1647068009546)(D:/Typora/image-20220111231635073.png)]

params参数

如果使用params必须使用name 不能使用path 因为这个path已经找不到了。原路径预留的path有占位符:(路径参数)。

当一个路由被匹配时,它的 params 的值将在每个组件中以 this.$route.params 的形式暴露出来。

拿这个过去匹配不到

模板

路由命名

一个配置项命一个名

原来的path改成name也可以正常使用 必须要写成对象然后配置name 写成字符串就是默认是路径了

props

以props的形式组件间传参数

params版

query版:

router-link(声明式路由导航) push

有点像数组那种 一层一层追加再一层一层退出 默认就是push模式 replace

有点像无痕浏览 是采用取代 历史记录只有一条

编程式路由导航(不借助routerlink的路由导航)

不使用router-link的路由导航,用this.$router使用路由器对象来进行路由的切换

// 字符串路径 

router.push('/users/eduardo')// 带有路径的对象

router.push({ path: '/users/eduardo' })// 命名的路由,并加上参数,让路由建立 url params参数地址栏不显示参数

router.push({ name: 'user', params: { username: 'eduardo' } })// 带查询参数,结果是 /register?plan=private

router.push({ path: '/register', query: { plan: 'private' } })// 带 hash,结果是 /about#team

router.push({ path: '/about', hash: '#team' })

负数是后退 正数是前进 我感觉是读栈里面 前进就是往栈尾走 后退就是往后走(。 说一些废话

下面是后退两步(连点两下后退

面试题:

1.路由传递参数(对象写法) path是否可以结合params参数一起使用?

不可以 会报错 params和name一起用

this.$router.push({ path: '/Search/', params: { keywords:this.keywords } }) 

Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: “/Search/”.

2.如何指定params参数可传可不传

3.params传空串

我的url有点问题 明明已经跳转到login了 但是还是显示这个

ps:路由规则是这样的

{path: "/Login/:keywords",component:Login ,name:"Login",meta:{showFooter:"false"} 

},

4.路由能不能使用props

可以,

1)布尔值

在接收的路由组件路由规则上加props

{path: "/Login/:keywords",component:Login ,name:"Login",meta:{showFooter:"false"},//传布尔值props:true//传对象props:{keywords:"1111111111"}//传函数props:(route)=>({params:route.params,a:1,b:2})} 

},

然后照常使用就ok

<script> 

export default {

name:"Login",

props:["keywords"]

}

</script>

解决 错误NavigationDuplicated: Avoided redundant navigation to current location

这个错误主要是已经在这个页面然后路由又要转到这个页面导致的

goSearch() {console.log("goSearch");let re = this.$router.push({ name: "Login", params: { keywords: this.keywords } }// ,// () => {// // console.log("yes");// },// () => {// // console.log("no");// });console.log(re);//Promise对象}, 

 goSearch() {console.log("goSearch");let re = this.$router.push({ name: "Login", params: { keywords: this.keywords } },() => {console.log("yes");return 1},() => {console.log("no");});console.log(re);//undefined}, 

不知道为什么会这样 加了两个函数返回的变成undefined了…

重写push、replace

const originalPush = VueRouter.prototype.push 

VueRouter.prototype.push = function push (location) {return originalPush.call(this, location).catch(err => err)

}

缓存路由组件 keep-alive

include里面填的组件名

home.vue

<router-link active-class="active" to="/home/next">next</router-link> 

<keep-alive><router-view></router-view>//缓存的是跳转的那个next组件</keep-alive>

路由组件独有的生命周期钩子

next.vue

<script> 

export default {name:'next',beforeDestroy() {console.log("next被销毁了")},activated() {console.log("home actttttt")},deactivated() {console.log("home deactttt")},

}

</script>

重定向

通过配置route

router/index.js

 {// 重定向 访问/的时候,让它定位到path:'*',redirect:'/home'} 

也可以写别的path 下面例子是从 /a 重定向到 /b

const router = new VueRouter({routes: [{ path: '/a', redirect: '/b' }] 

})

甚至是一个方法,动态返回重定向目标:

const router = new VueRouter({routes: [{ path: '/a', redirect: to => {// 方法接收 目标路由 作为参数// return 重定向的 字符串路径/路径对象}}] 

})

注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在下面这个例子中,为 /a 路由添加一个 beforeEnter 守卫并不会有任何效果。(这个写法没有看过 下次遇到写写看 路由守卫 路由前置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rw6CvKZC-1647068009576)(D:/Typora/image-20220113021733886.png)]

meta元数据(就是所谓的路由元信息了) 配置对象里面的不能随便加属性的,自己在配置对象里面加的属性是读不到的 ,会被无视掉 要放属性就放到meta里面

我们称呼 routes 配置(就是router/index.js 暴露的那个全局路由)中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,它可能匹配多个路由记录。

例如,根据上面的路由配置,/posts/new 这个 URL 将会匹配父路由记录 (path: '/posts') 以及子路由记录 (path: 'new')。

一个路由匹配到的所有路由记录会暴露为 $route 对象(还有在导航守卫中的路由对象)的$route.**tched 数组。我们需要遍历这个数组来检查路由记录中的 meta 字段,但是 Vue Router 还为你提供了一个 $route.meta 方法,它是一个非递归合并所有 meta 字段的(从父字段到子字段)的方法。这意味着你可以简单地写

router.beforeEach((to, from) => {// 而不是去检查每条路由记录// to.**tched.some(record => record.meta.requiresAuth)if (to.meta.requiresAuth && !auth.isLoggedIn()) {// 此路由需要授权,请检查是否已登录// 如果没有,则重定向到登录页面return {path: '/login',// 保存我们所在的位置,以便以后再来query: { redirect: to.fullPath },}} 

})

路由后置

独享路由守卫(只有前置没有后置)

只对某一个组件进行限制

组件内路由守卫

通过路由规则进入退出分别调用beforeRouterEnter,beforeRouterLeave。

进入组件跟离开组件与之前的前置/后置路由守卫完全不一样。前置、后置路由守卫是有一点点像钩子,自动启动,然后我觉得组件内路由守卫更像我本人,推一下动一下。。

点了button路由进入home组件才启动,离开home组件 切换才启动

又及 不通过路由规则 直接展示路由组件是不会触发beforeRouterEnter,beforeRouterLeave的

eg

直接放home组件没有触发 由于有初始化还是触发了前置、后置路由守卫(beforeEach、afterEach)

总结:

路由器的两种工作模式

可以使用nignx/node的一个中间件完成匹配

ui组件

转载:感谢您阅览,转载请注明文章出处“来源从小爱孤峰知识网:一个分享知识和生活随笔记录的知识小站”。

链接:vue2学习笔记vue2记录http://www.gufeng7.com/niaolang/1822.html

联系:如果侵犯了你的权益请来信告知我们删除。邮箱:119882116@qq.com

标签: