目录
1. 计算属性
1.1 计算属性的特点
2. 内容分发
2.1 使用插槽的示例
3. 自定义事件
1. 计算属性
什么是计算属性 ?
计算属性的重点突出在属性两字, 首先它是个属性, 其次这个属性有计算的能力, 这里的计算就是个函数; 简单来说, 它就是一个能够将计算结果缓存起来的属性 (将行为转化成了静态的属性), 仅此而已; 可以想象为缓存!
代码示例 :
<div id="app">
<p>currentTime1: {{currentTime1()}}</p>
<p>currentTime2: {{currentTime2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js">
</script>
<script>
var vm = new Vue({
el: "#app",
data: {
msg: "hello vue"
},
methods: {
currentTime1: function() {
return Date.now(); // 返回一个时间戳
}
},
computed: { // 计算属性 注意: methods, computed 方法不能重名, 重名之后只会调用 methods 方法
currentTime2: function() {
return Date.now(); // 返回一个时间戳
}
}
});
</script>
说明:
- methods : 定义方法, 调用方法使用 currentTime1(), 需要带括号;
- computed : 定义计算属性, 调用属性使用 currentTime2, 不需要带括号;
【注意】methods 和 computed 中的方法不能重名
如果二者方法重名了, 就只会调用到 methods 中的方法. 请看如下示例 :
访问页面 :
1.1 计算属性的特点
针对上述代码示例, 对比调用 methods 和 computed 方法的变化 :
1. 控制台调用 methods 中的方法 :
每次调用 currentTime1, 时间戳都会发生改变.
2. 控制台调用 computed 中的方法 :
每次调用 currentTime2, 时间戳不会发生变化. 计算出来的结果被缓存在内存中了.
【注意变化】
此时我在 computed 中调用一下 data 中的 msg 数据, 并在控制台中不断调用 computed 中的currentTime2 过程中, 突然修改一下 msg 的值, 再去调用 currentTime2, 此时观察变化 :
当 computed 中其他数据刷新时, currentTime2 的时间戳就会重新计算, 这个和缓存一模一样.
【结论】
调用方法时, 每次都需要进行计算, 既然有计算过程则必定产生系统开销, 那如果这个结果是不经常变化的的呢 ? 此时就可以考虑将这个结果缓存起来, 采用计算属性可以很方便的做到这一点, 计算属性的主要特征就是为了将经常变化的计算结果进行缓存, 以节约我们的系统开销;
2. 内容分发
在 Vue.js 中我们使用 <slot> 元素作为承载分发内容的出口, 作者称其为 "插槽", 可以应用在组合组件的场景中.
为什么需要插槽 ? 比如当我们遇到以下场景时 :
<div id="app">
<p>列表书籍</p>
<ul>
<li>Java</li>
<li>Linux</li>
<li>Python</li>
</ul>
</div>
按照原先的方式, 我们想要拿到 li 中的所有数据, 就得遍历 ul, 可现在 ul 里面隔了 li , 此时再按照之前的方式遍历就会出问题, 于是就需要使用到 "插槽" 来解决
2.1 使用插槽的示例
准备一个待办事项组件 (todo), 该组件由待办标题 (todo-title) 和待办内容 (todo-items) 组成, 但是这三个组件又是互相独立的, 如何使用插槽来实现 ??
1. 定义一个待办事项的组件 :
<div id="app">
<todo>
</todo>
</div>
<script>
Vue.component("todo",{
template: '<div>\
<div>列表书籍</div>\
<ul>\
<li>Java</li>\
</ul>\
</div>'
});
</script>
2. 让待办事项的标题和值实现动态绑定. 我们给上面的待办事项的标题和值都留出一个插槽. <slot> 标签
<div id="app">
<todo>
</todo>
</div>
<script>
Vue.component("todo",{
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
</script>
3. 定义 todo-title 的待办标题组件和 todo-items 的待办内容组件.
// 待办标题组件
Vue.component("todo-title",{
props: ['title'],
template: '<div>{{title}}</div>'
});
// 待办内容组件
Vue.component("todo-items",{
props: ['item','index'],
template: '<li>{{index}}--{{item}}</li>'
});
4. 实例化 Vue, 并初始化数据
var vm = new Vue({
el: "#app",
data: {
title: "跟秦老师学 Vue",
todoItems: ['你好世界','毛毛学hadoop','毛毛学Linux']
}
});
5. 将这些值通过插槽插入, 实现组合组件的内容分发.
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index"></todo-items>
</todo>
</div>
浏览器访问 :
由此可见, 插槽在组合组件中实现内容分发起了关键作用.
3. 自定义事件
既然 Vue 它是双向绑定的, 那我们如何针对上述内容分发的示例, 实现动态的删除呢 ??
分别在 todo-items 组件和 vm 实例中增加删除方法 :
Vue.component("todo-items",{
props: ['item','index'],
// 只能绑定当前组件的方法
template: '<li>{{index}}---{{item}} <button @click="remove">删除</button></li>',
methods: {
remove: function() {
alert("删除成功!");
}
}
});
var vm = new Vue({
el: "#app",
data: {
title: "秦老师说 Vue",
todoItems: ['你好世界','毛毛学hadoop','毛毛学Linux']
},
methods: {
removeItems: function (index) {
this.todoItems.splice(index,1);
}
}
});
但是现在问题是, todo-items 组件中无法绑定 vue 实例中的方法, 一旦我把 @click="remove" 写成 @click="removeItems", 访问页面的时候, 就会报 removeItems 未定义的错误.
于是 Vue 就为我们提供了自定义事件的功能帮助我们解决这个问题 ,
使用 this.$emit("自定义事件名", 参数), 具体操作如下 :
1. View 层模板绑定 Vue 实例中的方法
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index" v-on:remove="removeItems(index)"></todo-items>
</todo>
</div>
2. todo-Items 组件中使用 this.$emit() 绑定 view 模板中的自定义事件
ue.component("todo-items",{
props: ['item','index'],
// 只能绑定当前组件的方法
template: '<li>{{index}}---{{item}} <button @click="remove">删除</button></li>',
methods: {
// this.$emit 自定义事件分发
remove: function(index) {
this.$emit('remove',index);
}
}
});
此时就能动态的对数据进行删除了.
自定义事件原理图 :