vue笔记4
12.自定义指令
v-if、v-show等是vue默认设置的核心指令,除此之外,vue也允许注册自定义指令。
自定义指令一般用在需要对纯DOM元素进行底层操作的情况。
自定义指令的注册类似于组件的注册,包括全局指令和局部指令两种。
1.全局指令
//注册一个全局指令 v-focus
//在实例化对象Vue外部,调用Vue的构造方法
Vue.directive('focus',{
inserted:function(el){
//inserted是钩子函数,表示该指令在绑定的元素被插入到DOM时触发
el.focus()
//el事件对象返回的是绑定该指令的DOM元素
}
})
2.局部指令
let vm = new Vue({
el:'#app',
directives:{
focus:{
inserted:function(el){
el.focus()
}
}
}
})
自定义指令注册后,直接在对应的标签上绑定即可使用
<div id="app">
<input v-focus>
</div>
自定义指令的钩子函数
钩子函数定义了自定义指令的不同生命周期
- bind : 只调用一次。指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作
- inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
- update: 所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。
- componentUpdated: 所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
- unbind: 只调用一次, 指令与元素解绑时调用。
区别:
- bind与inserted:bind时父节点为null,inserted时父节点存在;
- update与componentUpdated:update是数据更新前,componentUpdated是数据更新后。
钩子函数的参数:
el:指令绑定的元素,可以直接用来操作DOM
binding:一个对象,包含指令名称以及该指令绑定的表达式信息
vnode:vue编译生成的虚拟节点
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
###除了 el 之外,其它参数都是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
函数简写形式:
//大多数情况下,可能想在bind和update钩子上做重复动作,并且不想关心其它的钩子函数。可以这样写:
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
13.生命周期函数
- 生命周期函数:在Vue对象实例创建、运行、销毁的过程中,在不同的时间会执行不同的事件,这些事件称为生命周期函数。
- 生命周期函数=生命周期钩子=生命周期事件
- 主要生命周期函数的分类:
- Vue对象实例化期间:
- beforeCreate:vm对象实例正在创建中,但是data和methods属性都没有初始化,所以在这个生命周期无法访问到vm对象的methods和data属性
- created:实例对象已经在内存中创建完成,data和methods也已经初始化完成,所以在这个生命周期可以访问到vm对象的属性
- beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
- mounted:挂载到dom上。这个函数执行标志vm和dom成功关联=>可以操作vm来间接操作dom
- 运行期间的生命周期函数:
- beforeUpdate:状态更新之前。此时data中的数据是最新的,但是界面显示的数据还是旧的,dom节点还没有被重新渲染
- updated:实例对象被更新完毕之后调用,data中的数据和页面显示一致。此时页面已被重新渲染。
- 销毁期间的生命周期函数:
- beforeDestroy:实例对象vm销毁之前调用。在这个生命周期,实例化对象仍然可以被操作。
- destroyed:Vue实例销毁后调用。调用后Vue实例指示的所有东西都会解绑。所有事件监听器,子实例也会被销毁。(但是定时器不会被销毁,因为定时器是window调用的,所以可能需要进行清除定时器的操作)
beforeCreate(){
//vm对象实例化之前 data没有构建出数据,methods也没有构建出方法
//这个函数能不能做网络请求?
---可以,但是请求的数据不能操作data的数据源,因为此时data还没有生成 可以做预加载
}
created(){
//vm对象实例化完毕
//vm对象创建完毕,所以可以使用vm对象的功能,即可以访问到data,但是不能操作dom,因为还没挂载到页面
//如果希望网络请求加载的数据一下给用户呈现,就在这里请求页面的数据
}
beforeMount(){
//虚拟节点树挂载到真实节点树之前
}
mounted(){
//虚拟节点树已经挂载到真实节点树
//页面已经挂载,此时既能操作vm,也能操作dom,此函数调用时,页面结构已经显示
//ajax请求在个函数中 可以在这个周期做网络请求,页面加载了之后的所有业务,都可以在这里执行
//这个函数执行标志 vm和dom成功的关联,可以通过操作vm来操作dom
}
//以上生命周期函数只会在整个流程中被执行一次
===========
beforeUpdate(){
//数据改变,页面刷新之前 此时data的数据是最新的数据,但是页面显示的数据尚未刷新
//页面首次加载时不执行此函数
//debugger //可以暂停代码执行
}
updated(){
//页面已经更新 此时data的数据和页面的数据一致
}
beforeDestroy(){
//vm销毁之前
//最后能够访问到vm对象的函数
//常用于保存用户的配置信息(如用在视频播放器中记录视频播放位置等)
//销毁实例化对象的函数
//this.$destroy();
}
destroyed(){
//vm已经销毁
//无法操作vm对象
//可以做清除计时器的功能
//中断网络
}
注意点:
- beforeCreate() ,created(), beforeMount(), mounted(), destoryed(),这些钩子都只执行一次
- beforeUpdate(), updated(),在页面首次加载时不会被调用,页面首次加载后,当data的数据改变时,就会被调用
- beforeDestroy(), destroyed(), 销毁的方式有两种:用户关闭和代码this.$destroy()//销毁vm实例
- 网络请求不能放在beforeUpdate(), updated()中,因为发送请求,获取数据会,会改变data的值,data改变会触发这两个钩子,会陷入死循环。
- 只有两个函数无法访问vm对象的成员:
beforeCreate()和destroyed();
面试题
1. DOM 渲染在 哪个周期中就已经完成
答:mounted
2. 页面第一次渲染哪些钩子执行 顺序是什么
答:beforeCreate created beforeMount mounted
3.哪些钩子能做网络请求 哪些能请求页面数据
所有钩子都能
但是操作vm的话 就必须在 created beforeMount mounted
updata/beforeUpdate 可以访问vm但是不能请求数据用于显示 因为会造成死循环
4.网络请求应该在什么钩子中,为什么?
答:可以放在data生成以后更新数据之前 的所有钩子中
具体的更具业务需求来 常见的放在created或者mounted中
因为网络请求下来的数据 常常会存在data容器中
created:因为有时候我们希望异步的网络请求和vm的挂载同时进行 体现出CPU多核的优势
mounted:因为有时候我们希望本地的UI骨架已经加载完毕以后再去请求数据刷新UI
5.为什么要用生命周期函数?
答:a.把整个运行期间的业务区分的很明显
b.能够更好的帮助我们把产品的业务逻辑实现了
c.更有利于我们维护产品 和 修改需求
d.能够让我们写出更高质量的产品的代码
14.组件
组件是可以复用的Vue实例 具有相同特征不同数据的模块 把它集成为一个组件 供重复利用
组件类似于自定义标签,该标签的内容会被定义的组件模板完全替换
- 组件的属性不能使用大写字母
- 组件的名字命名注册时可以使用驼峰命名法,但是在模板中使用时需要使用连字符连接(因为标签不识别大小写)
- 注册的组件不能跟系统组件重名
- 组件使用时最好不用单标签(多次使用只会显示第一个)
<div id="app">
<abc></abc>
</div>
<script>
new Vue({
el:"#app",
data:{},
components:{
"abc":{
data(){
return{
msg:"hello"
}
},
template:`<div>
abc
</div>`
},
})
</script>
//页面加载后,标签<abc>会被替换为模板template内的结构:"<div>
abc
</div>"
全局组件
全局组件的注册:调用vue的component方法。
参数1:组件名,参数2:包含组件所需方法的对象
<script>
Vue.component("all",{
template:`<h1>all</h1>`
})
new Vue()
</script>
局部组件
一个vm实例可以有多个局部组件,但是只能供当前vm实例使用
同时,局部组件中也只能访问到当前vm实例的属性
局部组件中也具有自己的过滤器,计算属性,方法,生命周期函数等
<script>
Vue.component("all",{
template:`<h1>all</h1>`
})
Vue.component("all2",{
template:`<h1>all</h1>`
})
new Vue({
el: '#app',
data: {
msg:"vue"
},
components:{
"myHead":{
template:`<div>
myhead
<all/>
</div>`
},
"hq":{
data(){return {
msg:"hello"
}},
template:`<div>
<h1>{{msg}}</h1>
<h2>666666</h2>
<son></son>
<all></all>
</div>
`,
components:{
son:{
template:`<h1>son
<all/>
</h1>`
}
},
methods:{},
filters:{},
computed:{},
watch:{},
directives:{},
beforeCreate(){},
created(){},
beforeMount(){},
mounted(){},
beforeUpdate(){},
updated(){},
beforeDestroy(){},
destroyed(){}
}
}
})
</script>
单文件组件
, methods:{}, filters:{}, computed:{}, watch:{}, directives:{}, beforeCreate(){}, created(){}, beforeMount(){}, mounted(){}, beforeUpdate(){}, updated(){}, beforeDestroy(){}, destroyed(){} } } })
##### 单文件组件
引入:@1官方脚手架 @2挂载vm对象 @3组件引入并渲染到vm中
|