1、计算属性 vs 监听器
1.1、监听器更通用 , 理论上计算属性能实现的侦听器也能实现 处理数据的场景不同,
1.2、监听器适合一个数据影响多个数据,计算属性适合一个数据受多个数据影响
1.3、计算属性有缓存性 , 计算所得的值如果没有变化不会重复执行
1.4、监听器适合执行异步操作或较大开销操作的情况
watch:
选项:deep
为了发现对象内部值的变化,可以在选项参数中指定 deep: true。注意监听数组的变更不需要这么做。
选项:immediate
在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调。
2、神奇的模板语法是如何实现的
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少 需要重新渲染多少组件,并把 DOM 操作次数减到最少。
// 输出vue替我们生成的渲染函数一窥究竟
console.log(app.$options.render)
// 它长这个样子
(function anonymous(
){
with(this){return _c('div',{attrs:{"id":"app"}},[_c('h2',{attrs: {"title":title}},[_v("\n "+_s(title)+"\n ")]),_v(" "),_c('input',{directives:[{name:"model",rawName:"v-model",value: (course),expression:"course"}],attrs:{"type":"text"},domProps:{"value": (course)},on:{"keydown":function($event) {if(!$event.type.indexOf('key')&&_k($event.keyCode,"enter",13,$event.key,"Enter" ))return null;return addCourse($event)},"input":function($event) {if($event.target.composing)return;course=$event.target.value}}}),_v(" "),_c('button',{on:{"click":addCourse}},[_v("新增课程")]),_v(" "),(courses.length == 0)?_c('p',[_v("没有任何课程信息")]):_e(),_v(" "),_c('ul',_l((courses),function(c){return _c('li',{class:{active: (selectedCourse === c)},on:{"click":function($event){selectedCourse = c}}}, [_v(_s(c))])}),0)])}
})
改写为渲染函数版本试试,02-cart-render.html,功能一模一样
const app = new Vue({
// 引入上面的render函数 render() {
with (this) { return ... } }
})
结论:Vue通过它的编译器将模板编译成渲染函数,在数据发生变化的时候再次执行渲染函数,通过对 比两次执行结果得出要做的dom操作,模板中的神奇魔法得以实现。
如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,也可以不用模板,直接写渲染 (render) 函数 。
这些功能到底是怎么实现的,我们将继续探究.....
3、探讨生命周期
3.1、从一道面试题开始
关于Vue的生命周期,下列哪项是不正确的?()[单选题]
A、Vue 实例从创建到销毁的过程,就是生命周期。
B、页面首次加载会触发beforeCreate, created, beforeMount, mounted, beforeUpdate, updated。
C、created表示完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来。
D、DOM渲染在mounted中就已经完成了。
3.2、结论:
三个阶段:初始化、更新、销毁
初始化:beforeCreate、created、beforeMount、mounted
更新:beforeUpdate、updated
销毁:beforeDestroy、destroyed
也有常用:
- activated : keep-alive 缓存
- deactivated : keep-alive 缓存 激活|休眠
- errorCaptured : 250版本,子孙组件错误捕获、处理错误。
3.3、使用场景分析:通常使用:带上before的用的少
{
beforeCreate(){} // 执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务
created(){} // 组件初始化完毕,各种数据可以使用,常用于异步数据获取
beforeMount(){} // 未执行渲染、更新,dom未创建
mounted(){} // 初始化结束,dom已创建,可用于获取访问数据和dom元素
beforeUpdate(){} // 更新前,可用于获取更新前各种状态
updated(){} // 更新后,所有状态已是最新
beforeDestroy(){} // 销毁前,可用于一些定时器或订阅的取消,组件实例还在
destroyed(){} // 组件已销毁,作用同上,组件实例不在了
}
4、组件
0、为什么组件化:!!!软件工程化:高内聚、低耦合。
1、推荐引入组件也是羊肉串命名法。减少引入是驼峰,(ele中使用是羊肉串)的转换和混淆。组件自定义事件也是羊肉串命名,同理。
2、props:传入数据,最好都是约定好的类型,对象key:value/default,让程序更健壮。
3、组件内的data: 必须是函数式的return {}。原因很简单:组件可能是多实例的应用,要保证每个实例的data互不影响,没有引用相同的数据源。
4、vue组件/react组件 都是《单根元素》。
4.1、父级组件收到子级组件事件的数据,减少写冗余的事件函数, 可以直接使用 $event 拿到值。
<message :show="show" @close="show=$event"></message>
4.2、新出了 .sync 语法糖,减少老爹的冗余事件函数
// 父组件
// 类似show.sync="show" @update:show="xxxxx"
<message :show.sync="show"></message>
// 子组件,约定死了自定义事件名称 'update:show'。
Vue.component('message', { props: ['show'], template: `
<div class="message-box" v-if="show">
...
<span @click="$emit('update:show',false)">x</span>
</div>
5、组件上使用 v-model 只是一个语法糖 (让组件内部无状态,更依赖父级组件,变得更复用)
方法1、(常用)
<!-- 自定义组件支持v-model需要实现内部input的:value和@input -->
props: ['value'],
methods:{
onXxx(e){
this.$emit('input',e.target.value);
}
}
方法2、 (推荐) 2.2.0+ 新增
v-model默认转换是:value和@input,如果想要修改这个行为,可以通过定义model选项
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
5、通过插槽分发内容
原因:(让组件内部无状态,更依赖父级组件,变得更复用) ),类似:厕所留下几个坑位,将来谁来,我不管!
1、通过使用vue提供的 元素可以给组件传递内容。 具名插槽、默认插槽、作用域插槽
<message :show.sync="show">
<template v-slot:title>{{titleText}}</template>
<template>新增课程成功!</template>
</message>
...
data:{titleText:'恭喜'}
// 具名插槽、默认插槽
Vue.component('message', { props: ['show'], template: `
<div class="message-box" v-if="show">
<slot name="title"></slot>
<slot></slot>
</div>
`
})
// 作用域插槽
// 插槽内容里面的变量 又来自子组件中,需要临时的改变上下文
// 父级
<message :show.sync="show">
<template v-slot:title="slotSelf">{{slotSelf.titleText}}</template>
</message>
// 子级
Vue.component('message', { props: ['show'], template: `
<div class="message-box" v-if="show">
<slot name="title" titleText="子级自己的变量哦">默认标题</slot>
</div>