两个重要的小原则
- 被Vue管理的函数,最好写成普通函数,这样this才是指向vm或者组件对象
- 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数),最好写成箭头函数,这样this才是指向vm或者组件实例对象
1. 计算属性与方法的区别
1. 在vue模板渲染中,当为某个元素绑定方法时,那么模板每次渲染的时候,这个方法都会被执行一次,因为method没有缓存。不同的是,computed计算属性具缓存功能,即当你为元素绑定的是计算属性的时候,由于计算属性具有缓存功能,因此模板每次渲染的时候,不会重新去执行这个计算属性,而是找到这个计算属性的缓存之,当且计算属性依赖的属性发生变化的时候,才会重新去执行这个属性。
2.由于计算属性的返回值是通过已有属性计算并return的,因此因为这个特别性质,计算属性是不可以进行一些异步操作的。如下:
3. computed能完成的,watch都可以完成
4. watch能完成的,computed不一定能完成,例如,watch能进行异步操作
1.1 计算属性的完整写法
每一个计算属性都具有两个方法,get()与set(),详细写法如下:
computed: {
fullName: {
get(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName;
},
set(value){
console.log('set被调用了');
const str=value;
str=value.split('-')
this.firstName=str[0];
this.lastName=str[1]
}
}
}
当你所用到的计算数据只考虑读取,不考虑修改的情况,那么可以使用简写方式:
computed:{
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName;
}
}
那么,在计算属性中,get与set分别在什么时候开始调用呢?
- get:当有人读取这个计算属性fullName的时候,get会被调用,且返回值就作为fullName的值
- set:初次读取fullName时,所依赖的数据发生变化时
1.2 计算属性的相关说明
- 定义:要用的属性不存在,需要通过已有属性计算得来
- 原理:借助了Object.defineProperty方法提供发getter和setter
- get函数什么时候执行?
(1)初次读取数据时会执行一次(因为具有缓存)
(2)当依赖的数据发生变化时会被再次调用
4. 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试更加方便
5.备注:
(1)计算属性最终会出现在vm上,直接读取即可
(2)如果计算属性要被修改,那必须写set函数去相应修改,且set中要引起计算时依赖的数据发生变化
2. watch监视属性
- 当被监视的属性变化时,回调函数hander自动调用,进行相关的操作
- 监视的属性必须存在,才能进行监视!!
- 监视的两种写法
(1)new Vue时传入的watch配置
(2)通过vm.$watch监视
2.1 watch监视的表示
watch:{
isHot:{
immediate:true,
//handler什么时候调用?即是isHot发生改变的时候
handler(newValue,oldValue){
//这里通常可以根据新旧值之间的变化而执行有些操作
console.log('isHot被修改了,新值为:'+newvalue+'旧值为:'+oldvalue)
}
}
}
ps:
- 这里watch监视的是isHot属性,你可以尝试改变isHot的值,你会发现便会触发isHot中的handler函数,控制台输出相应的提示;
- isHot是一个对象,其中具有多个配置属性,这里immediate表示isHot被初始化的时候调用,而handler则是isHot发生改变的时候再触发。
2.2 watch深度监听
深度监听是可以监听对象内部值的变化
- Vue中的watch默认不检测对象内部值的变化(它只能监听一层)
- 配置deep:true可以监听对象内部值的变化(多层数据结构)
备注:Vue自身是可以监听对象内部值的改变,但是Vue提供的watch默认不可以
使用watch时,根据数据的具体结构,决定是否采用深度监听
注意 :watch的监听建立在已经存在的属性上,注意下面错误示范
错误方式①:
data: {
numbers: {
a: 1,
b: 2
}
}
watch: {
a: {
handler(){
console.log('a被改变了')
}
}
}
错误方式②
因此,正确的方式是,为该属性开启深度监听
还要要注意一个问题是,当使用简写的方式进行属性监听的时候,只有该属性不需要配置其他属性时,比如深度监听或者初始化时监听
2.3 vue循环列表中绑定:key的作用
首先按官网介绍的,可以主要用在Vue的虚拟Dom算法,在新旧节点对比时辨识VNodes。使用key时,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。
有相同父元素的子元素必须有独特的key,重复的key会造成渲染错误。
vue中循环列表时,绑定:key的值往往有两种方式,一是将循环列表的索引值index作为key,而是根据返回数据中的唯一标识作为key。不管以什么方式绑定key,key的值在列表中必须是唯一的,可以使用index的原因是索引值必然是唯一的。、
以下举例子说明以index或者唯一标识符绑定key的时的执行流程
2.3.1 index作为key
1.比如有初始数据如下:
{id:'001',name:'张三',age:'18'},
{id:'002',name:'李四',age:'19'},
{id:'003',name:'王五',age:'20'}
2. 在模板使用v-for循坏该数据。以列表li的形式显示
<ul>
<li v-for="(index,item) in data" :key="index">
{item.name} - {item.age}
<input type="text">
</li>
</ul>
3. 那么vue会根据数据生成虚拟DOM,生成的虚拟DOM形式如下:
<li key="0">张三 - 18 <input type="text"></li>
<li key="1">李四 - 19 <input type="text"></li>
<li key="2">王五 - 20 <input type="text"></li>
4.将虚拟DOM转成真实的DOM
---------------------分割:以上是vue从绑定数据且从虚拟DOM转成真实DOM的过程----------------------
5.接下来说明数据发现变化时,key绑定值位index时数据的改变,改变数据如下
{id:'004',name:'老刘',age:'20'},
{id:'001',name:'张三',age:'18'},
{id:'002',name:'李四',age:'19'},
{id:'003',name:'王五',age:'30'}
6.此时由于数据变化了,那么vue就会重复数据渲染过程,此时根据新数据生成的虚拟DOM如下
<li key="0">老刘 - 30 <input type="text"></li>
<li key="1">张三 - 18 <input type="text"></li>
<li key="2">李四 - 19 <input type="text"></li>
<li key="3">王五 - 20 <input type="text"></li>
7.将虚拟DOM转成真实DOM
8.接下来解释为什么会出现以上的情况?
由于在vue中key时虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DON】与【旧虚拟DON】的差异比较,其中的比较规则如下:
(1)在旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 旧虚拟DOM中内容没有变化的时候,则直接使用之前的真实DOM(比如上面的input的内容)
- 若虚拟DOM中的内容发生变化了,则直接生成新的DOM,随后替换掉页面中之前的真实DOM
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key
- 直接创建新的真实DOM,随后渲染到页面上
(3) 由于以上例子并没有绑定key值,那么每次循环的时候key值都是自上而下从0-n,而自上而下input值没有发生改变,因此直接复用
3 Vue中数据绑定的原理
下面先同个例子来简单说明一下vue中的双向数据绑定
3.1 例子1
比如我想通过点击按钮来直接该百年数组persons中某一项的数据:this.persons[0]={id:'001',name:'马老师',age:'50',sex:'男'}
却发现页面没有跟新:
那么我们会发现,直接对persons数组中某一项进行更改是无效的,那么根据Vue双向数据绑定的原理,怎么样才能有效更改呢?
以下是有效的更改方式:(即是对数组项的指定属性进行修改)
this.persons[0].name='马老师';
this.persons[0].age=50;
this.persons[0].sex="男"
3.2 例子2
当你想给vue添加信新的属性时,也不能直接使用this.student.sex='男'进行增加,因此这样新增加的新属性是不具备数据的双向绑定的:
那么问题来了,应该怎么样添加新的属性才可以达到响应式呢?根据vue官网提示,当你不是一开始在data中定义的数据,直接添加是不具备响应式的,如果想又不是直接在data中添加,而是后期想用的时候在某个地方添加的时候,可以通过API实现,如下:
Vue.set(target,propertyName/index,value)
1. 参数:
- target :{Object |Array}
- propertyName/index:{ staring | number }
- value :{any}
2. 返回值:设置的值
3. 用法:
向响应式随想中添加一个property,并确保这个新peopety同样是响应式的,且出发视图更新。它必须用于相映式对象上添加新property,因为Vue无法探测普通的新增property(比如this.myObject.newProperty='hi')
注意:对象不能是Vue实例,或者Vue实例的根数据对象
实例:
methods: {
addSex() {
Vue.set(this.student, 'sex', '男')
}
}
3.3 例子3
3.4 总结
- Vue会监视data中所有层次的数据
- 如何检测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要检测的数据
(1)对象中后追加的属性。Vue默认不做响应式处理
(2)如需要给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(arget,propertyName/index,value)
3. 如何检测数组中的数据?
通过包裹数组跟新元素的方法实现,本质上就是做了两件事:(Vue中对操作数组的相关方法进行包装,可以达到数据双向绑定)
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面。
4. 在Vue修改数组中的某个元素一定要用如下方法:
(1)使用这个API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()、
(2)Vue.set() 或者 vm.$set()
特别注意:Vue.set()和vm.$set()不能给vm或者vm的根数据(vm._data)对象添加属性
4.收集表单数据
4.1 核心原理
核心是通过v-model指令和给表单元素添加value属性
注意,在使用v-model指令实现数据双向绑定时,v-model实质上接收到的是表单元素的value值。由于对于输入框比如“input、textarea”用户输入的值即为value值,因此不用额外给input绑定value值。而对于其他非输入框的表单元素(比如:radio、checkbox等),想要使用v-model实现双向绑定时,通常需为其添加value属性,
例子如下:
4.2 总结
- <input type="text"/>,则v-model收集的是value值,用户输入的就是value值
- <input type="radio"/>,则v-model收集的是value值,且要给标签配置value值
- <input type="checkbox"/>
(1)没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)配置input的value属性:
- v-model的初始值是非数字,那么收集的就是checked(勾选 or 未勾选,是布尔值)
- v-model的初始值是数组,那么收集的就是value组成的数组
4.v-model的三个修饰符
(1)lazy:失去焦点再收集数据
(2)number:输入字符串转为有效的数字
(3)trim:过滤首尾空格
5 过滤器
6. 指令
6.1 v-html指令
- 作用:像指定节点中渲染包含html结构的内容
- 与插值语法区别
(1)v-html会替换掉节点中所有的内容,{{xx}}则不会
(2)v-html可以识别html结构
3.严重注意:v-html有安全性问题!!
(1)在网站上动态渲染任意html是非常危险的,容易倒是xss攻击
(2)一定要在可信内容中使用v-html,永远不要在用户提交的内容上!(比如一些恶意人会通过其获取你的cookie等)
6.2 v-cloak指令
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时也买你展示出{{xxx}}的问题
6.3 v-once指令
- v-once所在节点在初次动态渲染后,就视为静态内容了(即只读一次)
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
6.4 v-pre指令
- 跳过其所在节点的编译过程
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
6.5 自定义指令
7 vue的生命周期
Vue的生命周期按执行顺序有:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestory、destoryed。
7.1 beforeCreate
vue在beforeCeate钩子函数中,进行了初始化、因为此时数据监测和数据代理还没开始,因此还无法通过vm访问到data中的数据、methods中的方法。
7.2 created
此时,已经完成数据检测、数据代理,因此可以在这里通过vm访问到data中的数据、methods中配置的方法。
注意:警告created之后,由于Vue并没有开始编译了,需要经过下面的beforeMount、mounted阶段才完成模板解析。
7.3 beforeMounted
此阶段vue已经开始解析模板、生成虚拟dom(内存中),页面还不能显示解析好的内容。即此时页面呈现的是未经Vue编译的DOM结构。所有对DOM的操作,最终都不奏效。
7.4 mounted
经过上面的beforeMount之后,此时vue已经将内存中的虚拟DOM转成真实的DOM插入到页面中了。
- 页面中呈现的是经过Vue编译的DOM
- 对DOM的操作均有效(尽避免操作DOM),至此初始化过程结束,
- 一般在此阶段运行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作。
7.5 beforeUpdate
经过上面的周期函数之后,页面已经渲染完毕,也可以相应数据。
在这里,如果数据发生变化,那么在这里数据新的,只不过页面是旧的,也就是说页面尚未和数据保持同步更新。
7.6 updated
这里根据新数据,生成新的虚拟DOM,随后与旧的虚拟DOM进行比较,最终完成页面的更新,即完成了Model->View的更新。此时,数据是新的,页面也是新的。即保持数据和页面同步。
总结图
8 组件
组件是可以复用的Vue实例,且带有一个名字。
关于VueComponent:
- school组件本质上是一个名为VueCompontent的构造函数,其不是程序定义的,是Vue.extend生成的。
- 我们只需要写<school/>或者<school><school/>,Vue解析时会帮我们创建school组件实例对象。即Vue帮我们执行的:new VueComponent(options)。
- 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!(Vue内部会自动帮我们执行new VueComponent(options))
- 关于this的指向:
- 组件配置中:
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this指向均是【VueComponent实例对象】
- 组件配置中:
2.new Vue()配置中
1.data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【Vue实例对象】
5.VueComponent的实例对象,可以简称为vc(组件实例对象)
Vue实例对象,简称vm
8.1 内置对象
8.1.1 以下先引入原型对象
function Demo(){
this.a=1,
this.b=2
}
//创建一个Demo的实例对象
const d = new Demo()
console.log(Demo.prototype)//显示原型属性
console.log(d.__proto__)//隐式原型属性
1.每个对象(或者构造函数)都有一个原型属性prototype
2.每个对象的实例都有一个隐形原型属性
3. 构造函数的原型属性和实例的原型属性均指向原型对象
Demo.prototype === d.__proto__
4.以下验证`Demo.prototype === d.__proto__`
//通过显示原型属性操作原型对象,追加一个x属性,值为99
Demo.prototype.x=99;
console.log('@',d.__proto__.x)
//或者直接输出d.x(因为找不到时也会往原型链上查找)
console.log(d.x)
8.1.2 Vue与VueCompontent的关系
- 一个重要的内置关系:VueConponent.prototype.__proto__ === Vue.prototype
- 为什么要这个关系:让组件实例对象vc可以访问Vue原型上的方法和属性
注意:实例的隐形原型属性,一定是指向自己构造这的原型对象,那么显而易见
Vue的实例对象vm的隐形属性指向Vue的原型对象
Vue的原型对象的原型属性又指向Object的原型对象
思考:那么Vue和VueComponent是如何联系起来的呢?
Vue内部将VueConponent的原型对象指向了Vue的原型对象(目的:使得不管是Vue实例还是VueConponent实例均能公用Vue的方法以及实例)
1.
比如我要在vc上找x属性,当vc上没有x属性时,会沿着__proto__上去找(这个proto指向VueCompontent的原型对象),当VueCompontent的原型对象上没有找到x时,则往proto上找x,此时,vue中将VueCompontent的原型对象的原型属性proto(指向了Vue原型对象),此时在Vue原型对象上找x,此可以找到,注意,如果在Vue的原型对象中也没有找到的时候,则继续往Vue原型对象的proto上找,即找到Object
9.render函数的理解
在入口文件main.js文件中,默认引入的vue不是完整版的,是vue开发者在vue完整版基础上改动的(这里称之为“残缺”版本),且这个引入的vue是不具备编译模板功能的。因此,当你在main.js入口文件,在创建Vue实例的时候,试图同时实现模板编译时,如下,是会出错的
报错如下:
因此,vue团队引入render函数,实现template模板编译,render函数的本质作用是生成节点
//完整版的rander函数
render(createElement){
return createElement('h1','你好啊') //render函数需要返回值
}
//简写
render:(q)=>{
return q('h1','你好啊')
}
//精简简写
render: q=>q(App)//这里的App是import引入的App.vue组件
//
new Vue({
el:'#app',
//下面这行代码,完成了将App组件放入容器中
render:h=>h(App)
})
思考:既然是要进行模板编译的,那为什么vue团队一开始不引入完整的,直接实现模板编译功能呢?原因是当你功能实现了之后,你的代码是需要通过webpack或者其他打包工具进行打包的,那么在进行打包之后,此时一些vue文件已经被编译成了浏览器能够识别的html、js、css等文件,那么在线上即是也不需要这个编译功能的。避免多此一举又占内存,因此vue团队一开始就是引入不带编译功能的vue。
疑问:如果引入的“残缺”版本的vue,那么在其他组件中的<template>标签是如何编译的呢?
答:vue中专门引入了一个包,用来解析组件中的额<template>标签
总结:关于不同版本的vue:
1. vue.js与vue.runtime.xxx.js的区别:
(1)vue.js是完整版本的Vue,包含:核心功能+模板解析器
(2)vue.runtime.xxx.js是运行版本的Vue,只包含:核心功能,没有模板解析器
2. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的ceateElement函数去指定具体内容。
9. 对脚手架进行功能定制化
1.使用vue inspect > output.js可以查看Vue脚手架的默认配置
2.新建一个vue.config.js可以对脚手架进行个性化定制,详见:配置参考 | Vue CLI
3. 脚手架的文件结构
10.ref属性
- 被用来给元素或者子组件注册引用信息(id的替代者)
- 应用在html标签(如div、h1等等)上获取的是DOM元素,应用在组件标签(.vue)上是组件实例对象(vc)
- 使用方式
打标识:<h1 ref="xxx">.....</h1>或者<School ref="xxx"></School>
获取:this.$refs.xxx
11. prop属性
prop属性在实现父子组件之间的通信中起到重要作用。
使用方式如下:
11.1 使用方式
父组件中: 在引入的子组件中直接:<子组件 变量名1="值1“ 变量名2="值2” :变量名3=“值3”/>
子组件中:
使用props属性进行接收父组件传过来的数据(使用props接收过来的数据,类似在data中定义的数据,直接挂在到vm上,因此在模板上可以直接使用,但是不能直接更改props中从父组件接接收过来的数据,可以间接改变,下面会讲到)
ps:当你想改变由父组件传递过来的数据时,不要企图直接修改,可以重新在data中定义一个变量来接收这个数据,然后通过更改data中这个新定义的变量去改变。
在父组件向子组件传递数据的时候,需要使用v-bind(简写:)指令告诉vue其中传入的时js表达式,而不是字符串。当你不适用v-bind指令的时候,那么vue就会默认你传入的数据时字符串类型。
11.2 单向数据流
- 所有的prop都使得其父子prop之间形成一个单向下行绑定:父级rpop的更新会向下流动到子组件中,但是反过来不行,这样会防止从子组件意外更变父组件的状态,从而导致你的应用的数据难以理解
- 额外的,每次父级组件发生改变时,子组件中所有prop都将会刷新到最新的值这样意味着你不应该在一个子组件内部中改变prop,如果你这样做了,vue会在浏览器的控制台中发出警告。
11.3 总结
功能:让组件接收外部传过来的数据
(1)传递数据:
<Demo name="xxx"/>
(2)接收数据:
第一种方式(只接收)
props:['name']
第二种方式(限制类型)
props:{
name:String
}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String,//类型
required:ture,//必要性
default:'老王'//默认值
}
}
12.minix 混入
混入提供了一种非常灵活的方式,来分发Vue组件中可复用的功能。一个混入对象可以包含任意组件的选项。当组件使用混入对象时,所有混入对象的选项将被“混入”进入该组件本身的选项。
例子:
1.定义一个混合对象
2.在组件中引入混合对象
3.总结
功能:可以把多个组件公用的配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){......},
methods:{...}
}
第二步使用混入,例如:
(1)全局混入:Vue.mxiin(xxxx)
(2)局部混入:mixins:['xxxx']
13. 插件
插件通常用来为Vue添加全局功能,插件的功能范围没有严格的限制---一般有下面几种:
- 添加全局方法或者property。如:vue-custom-element
- 添加全局资源:指令/过滤器/过渡等。如vue-touch
- 通过全局混入来添加一些组件选项。如vue-router
- 添加Vue实例方法,通过把它们添加到Vue.prototype上实现。
- 一个库,提供自己的API,同时提供上面提到的一个或多个功能,如vue-router
13.1 使用插件
使用全局方法Vue.use()适应插件,它需要在你调用new Vue()启动应用之前完成:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
new Vue({
// ...组件选项
})
13.2 总结
功能:用来做增强Vue
本质:包含install方法的一个对象,install的第一个参数是vue,第二个以后的参数是插件使用者传递的数据。
注意:在来引入插件之后,记得Vue.use()来使用插件(全局可使用)
14.样式
为了避免组件之间类名的重复而导致样式之间的冲突,因此在Vue中,给<style>标签提供了scope属性,加了scope之后,组件之间的样式互不影响。作用原理是每次渲染的时候,会给标签加上随机的属性,从而避免组件之间的样式冲突。
14.1 .同时,在vue中支持除css外的其他css编译器,如scss、less等,在<style>中的属性lang来指定你所用css处理器。
14.2. 问题:在npm下载less包时候与webpack发生冲突的解决
15. 自定义事件
1.一种组件通信的方式,使用于:子组件==>父组件
2.使用场景:A是父组件,B是字组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中,即在那里接受数据,就在那里设定事件的回调)
3.绑定自定义事件:
①第一种方式,在父组件中
<Demo @XXX="test"/> 或者 <Demo v-on:XXX="text"/>
⑤ 第二种方式,在组件中:
<Demo ref="demo"/>
......
mounted(){
//这个this.test是定义在methods中的函数,可以避免this指向的问题
this.$refs.xxx.$on('xxx',this.test)
}
③.若想自定义事件只能出发一次,可以使用once修饰符,或者$once方法
4.触发自定义事件:this.$emit('xxx',数据)
5.解绑自定义事件:this.off('xxx')
6.组件上也可以绑定原生DOM事件,需要使用.native修饰符
7.注意:通过this.$ref.xxx.$on('xxx',回调函数)绑定自定义事件时,回调要么配置在methods中,要么使用箭头函数,否者this指向会出现问题!
16. 全局事件总线
1.一种组件通信的方式,使用于任意组件间通信
2.安装全局事件总线:
new Vue({
.....
beforeCreate(){
Vue.prototype.$bus=this
}
})
3.使用事件总线:
1.接受数据:A组件想接受数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){
demo(data){
....
}
}
mounted(){
this.$bus.$on('xxx',this.demo)
}
2.提供数据:this.$bus.$emit('xxx',数据)
4.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
17.消息订阅与发布
17.1 说明
提供数据的是发布消息方
需要数据的是订阅消息方
17.2 下载相关插件
npm i pubsub-js
17.3 使用
- 使用import pubsub from 'pubsub-js'先将插件引入
- 在订阅消息方:
mouuted(){
pubsub.subscribe('hello',function(){
console.log('有人发布了hello消息,这里hello消息的回调执行了')
}
}
3.在消息发布方
methods(){
sendStudentName(){
pubsub.publish('hello',666)
}
}
4.取消订阅
17.4 总结
1.一种组件通信的方式,使用于任意组件间通信
2.使用步骤
1.安装pubsub:npm i pubsub-js
2.引入:import pubsub from ‘pubsub-js’
3.接受数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
methods(){
demo(data){
....
}
}
mounted(){
this.pid=pubsub.subscribe('xxx',this.demo)//订阅消息
}
4.提供数据:pubsub.publish('xxx',数据)
5.取消订阅,最好在beforeDestory钩子中,用PubSub.unsubscribr(pid)去取消订阅
18. nextTick()
- 语法:this.nextTick(回调函数)
- 作用:在下一次DOM更新结束后执行指定的回调
- 什么时候用:当改变数据后,要基于更新后的DOM进行某些操作时,要在nextTick()所指定的函数中执行。
- 使用场景:
比如在统一事件中,上一步你刚数据变化更改了试图,下一步又想获取DOM的时候,这时候你立即执行下一步,那么可能获取到的不是罪行的DOM,因此会影响页面效果,此时你使用this.nextTick()便可以得到解决。
19 HTML5 History模式与hash模式的区别
hash与history模式直观上的区别:
- hash模式:路径上带有#,比如:’http://localhost:8080/#/about/news‘
- history模式:正常的url:’http://localhost:8080/about/news‘
vue-router 默认的是hash模式,如果不想要很丑的hash,我们可以用路由的history模式,这种模式充分利用history.pushState API来完成URL跳转而无需重新加载页面
const router = new VueRouter({
mode: 'history',
routes: [...]
})
当你使用history模式时,URL就像正常url,例如http://yoursite.com/user/id,也好看!
不过这种模式还需要后台支持。因为我们的引用时单页客户端应用,如果没有后台正确的配置,当用户在浏览直接访问 http://oursite.com/user/id 就会返回404.
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html
页面,这个页面就是你 app 依赖的页面。