我们先来总结一下前面已经认识的选项
el:指定Vue实例的挂载点,根实例的特有属性
data:用于声明需要响应式绑定的数据对象
components:Vue实例配置局部注册组件
template:用于挂载元素的字符串模板
render:渲染函数,创建虚拟DOM,是字符串模板的替代方案。
现在开始一个例子介绍一下其他常用的选项(options对象的属性):
下面的代码局部注册了一个组件AgeStatistics,并把数据渲染到模板中
<div id="app">
<age-statistics inline-template>
<div>
<h1>**{{title}}</h1>
<table border="1">
<tr>
<th>编号</th><th>姓名</th><th>年龄</th>
</tr>
<tr v-for="(item,i) in list">
<td>{{i+1}}</td><td>{{item.name}}</td><td>{{item.age}} </td>
</tr>
</table>
<p>平均年龄:avg</p>
<div class="formGroup">
<input ref="name" type="text" v-model="currentPerson.name" placeholder="请填写姓名">
<input ref="age" type="text" v-model="currentPerson.age" placeholder="请填写年龄">
<button>添加</button>
</div>
</div>
</age-statistics>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script>
new Vue({
el: "#app",
data:{
title:'三年五班'
},
components: {
'AgeStatistics':{
data() {
return {
title:'学员统计',
list:[
{name:'张三',age:18},
{name:'李四',age:19}
],
currentPerson:{}
}
}
}
}
});
</script>
methods:方法
methods选项用于定义Vue实例的方法,methods选项是个对象,在其内部可以定义方法。
下面我们给button的click事件绑定一个方法add,组件的options种添加methods属性,实现点击按钮时新增一条记录
<button v-on:click="add">添加</button>
methods:{
add(e){
console.log(e);
console.log(event);
let _currentPerson = JSON.parse(JSON.stringify(this.currentPerson));
this.currentPerson={};
this.list.push(_currentPerson);
}
},
方法的参数
:
方法中可以获得绑定的事件event,绑定事件方法时:
- 如果不包含(),默认的参数是event,即上面代码中的e和event都指向事件对象;
- 如果包含(),参数e就是add传递的参数,如上面绑定的是add(),e即为undefined。
computed:计算属性
模板内的表达式可以用于简单运算,对于复杂的计算应当使用实例的计算属性computed
下面在computed中定义一个方法avg,显示到平均年龄处
<p>平均年龄:{{avg}}</p>
//计算属性
computed:{
avg(){
console.log('计算属性avg执行了');
let sum=this.list.reduce((sum, data) => {
return sum + parseInt(data.age);
}, 0);
return sum/this.list.length
}
},
计算属性对于从现有源组合新数据非常方便,与方法相比,它们的一大优点是缓存了输出。
即:如果独立于计算属性的某些内容在页面上发生更改,并且重新呈现UI。
computed中的方法会返回缓存的结果,不会重新计算;
methods中方法中会重新执行。
如在上例的methods增加一个方法avg2,来比较一下
<p>平均年龄:{{avg}}{{avg2()}}</p>
avg2(){
console.log('方法avg2执行了');
let sum=this.list.reduce((sum, data) => {
return sum + parseInt(data.age);
}, 0);
return sum/this.list.length
}
通过这个例子可以发现实现相同的功能methods中的方法代价更高。
另外你注意到了吗,在模板中调用它们的方式也不一样,在控制台中,我们发现avg是个属性,它的形式和data中的数据类似,但不拥有访问器属性get/set,而avg2是一个方法,所以avg2可以传参;
但avg如果要传参,需要使用闭包将属性值改为一个函数
<p>平均年龄:{{avg(2)}}</p>
computed:{
avg(){
return function (decimals) {
let sum=this.list.reduce((sum, data) => {
return sum + parseInt(data.age);
}, 0);
return sum/this.list.length.toFixed(decimals);
}
}
},
filters:过滤器
Vue.js 允许自定义过滤器,用于一些常见的文本格式化。
- 过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
- 过滤器应该被添加在JS表达式的尾部,由“管道”符号连接。
- 过滤器函数始终以表达式的值作为第一个参数。带引号的参数视为字符串,而不带引号的参数按表达式计算。
- 模板中调用过滤器函数时如果使用了参数,顺序称为过滤器函数的第二、三…个函数
- 可以添加多个过滤器
如前面的例子中,如果需要格式化平均年龄,保留一位小数点,可以这样做:
<p>平均年龄:{{avg | formatAge(1,'something')}}</p>
//过滤器
filters:{
formatAge(val,decimals){
return val.toFixed(decimals);
}
},
也可以全局定义过滤器,定义的方法和全局注册组件类似,要放到Vue实例化之前,如:
Vue.filter('formatAge', function (val) {
return val.toFixed(1);
})
watch:侦听属性
侦听属性watch的作用可以监控 Vue 实例上的数据变动,并调用其回调函数。
如:在watch中侦听数据title和currentPerson的变化,一旦变化就执行回调,其回调函数有两个参数,新值和旧值,如果侦听的数据是数组或对象,新值和旧值打印的结果是一样的。
watch: {
title(val, oldVal){
console.log(`监听到了title的变化:${oldVal}->${val}`);
},
currentPerson(val, oldVal) {
console.log('监听到了currentPerson的数据变动', val.age, oldVal.age);
},
}
handler方法和immediate属性
watch 中的方法最初绑定的时候是不会执行,如果希望一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch中title的监听方法,修改过后的代码如下:
/*title(val, oldVal){
console.log(`监听到了title的变化:${oldVal}->${val}`);
},*/
title:{
handler(val, oldVal){
console.log(`监听到了title的变化:${oldVal}->${val}`);
},
immediate:true
}
title绑定了一个handler方法,也就是设置回调函数,之前写的 watch方法其实默认写的就是这个handler。
深度监听 deep属性
watch 里面还有一个属性 deep,默认值是 false,代表是否深度监听,如在本例中currentPerson初次赋值时能够被handler监听到,重新赋值时监听不到,使用deep属性能够实现深度的监听。
currentPerson: {
handler(val,oldVal){
console.log('监听到了queryString的变化:',val.age,oldVal.age)
},
deep: true
},
props:用于接收来自父组件的数据
组件实例的作用域是孤立的。在子组件的模板内不能直接引用父组件的数据。父组件的数据需要通过 Prop 才能下发到子组件中,使用选项props申明该组件可接受的 prop 列表。
Prop可以理解为在组件上注册的一些自定义属性,这些属性的值可以通过组件的props选项接收到。
在本例中,在组件AgeStatistics中希望①获得根组件的数据title②获得静态属性bg-color,可以这样传递属性:
PS:html模板中属性要使用短横线分隔命名法(kebab-case)命名
<age-statistics v-bind:unit="title" bg-color="gray" inline-template>
...
<h1 :style="{backgroundColor: bgColor}">{{unit}}{{title}}</h1>
...
</age-statistics>
在组件实例的props选项中申明从父组件接受属性unit、bgColor。
props:['unit','bgColor'],
单向数据流
:父级 prop 的更新会向下流动到子组件中,但是反过来则不行;每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。