我们先来总结一下前面已经认识的选项
el:指定Vue实例的挂载点,根实例的特有属性
data:用于声明需要响应式绑定的数据对象
components:Vue实例配置局部注册组件
template:用于挂载元素的字符串模板
render:渲染函数,创建虚拟DOM,是字符串模板的替代方案。

现在开始一个例子介绍一下其他常用的选项(options对象的属性):

vue展示组件和容器组件 vue组件选项_vue展示组件和容器组件


下面的代码局部注册了一个组件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>

vue展示组件和容器组件 vue组件选项_字符串_02

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
  }
},

vue展示组件和容器组件 vue组件选项_字符串_03

计算属性对于从现有源组合新数据非常方便,与方法相比,它们的一大优点是缓存了输出。
即:如果独立于计算属性的某些内容在页面上发生更改,并且重新呈现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
}

vue展示组件和容器组件 vue组件选项_数据_04


通过这个例子可以发现实现相同的功能methods中的方法代价更高。

另外你注意到了吗,在模板中调用它们的方式也不一样,在控制台中,我们发现avg是个属性,它的形式和data中的数据类似,但不拥有访问器属性get/set,而avg2是一个方法,所以avg2可以传参;

vue展示组件和容器组件 vue组件选项_数据_05


但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);
   }
 }
},

vue展示组件和容器组件 vue组件选项_数据_06

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 都将会刷新为最新的值。