Vue 实例的选项

通常,模板内容较简单时,使用 data 配合表达式即可;涉及复杂逻辑时,可以用到 computed \ methods \ watch ...


el

el,是 element 的缩写,用于提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。

类型:string | HTMLElement
写法:
  el:'#app'   // 表示挂载目标为 id是‘app’的元素;
  或者 el:document.getElementById('app');

data

data,是 Vue 实例的数据对象。Vue 将会递归将 data 属性转换为 getter / setter,从而让 data 属性能响应数据变化。

类型:Object | Function
写法:组件的定义只接受 Function,所以推荐第二种;另,不应该对data使用箭头函数。
  data:{
    msg:'HelloWorld'
  }
  或
  data() {
    return {
      msg:'HelloWorld'
    }
  }
  • Vue 实例创建之后,可以通过 vm.$data 访问原始数据对象( data )。

Vue 实例代理了 data 对象上所有的属性,因此访问 vm.a等价于访问 vm.$data.a

  • _$开头的属性 不会被 Vue 实例代理,因为它们可能和 Vue 内置的属性、API 方法冲突。

你可以使用例如 vm.$data._property的方式访问这些属性。


computed 计算属性

类型:{ [key: string]: Function | { get: Function, set: Function } }
# 代码示例1
computed:{
	// 计算属性的getter,值为函数;this 指向 vm 实例
	transMsg:function(){
		return this.msg + '_你好,世界';
	}
}
 
# 代码示例2:计算属性默认只有getter,不过在需要的时候,也可以提供一个setter
var vm = new Vue({
	el:'#app',
	data:{
		name:'Hello'
	},
	computed:{
		saying:{
			get(){
				return this.name;
			},
			set(val){
				this.name = val;
			}
		}
	}
});
console.log(vm.saying);  // Hello
vm.saying = 'World';
console.log(vm.saying);  // World
// 不应该为一个计算属性使用箭头函数

计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。

计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。

注意,如果某个依赖(比如非响应式属性)在该实例范畴之外,则计算属性是不会被更新的。

var vm = new Vue({
  data: { a: 1 },
  computed: {
    // 仅读取,值只需为函数( 计算属性默认只有getter )
    aDouble: function () {
      return this.a * 2
    },
    // 读取和设置
    aPlus: {
      get: function () {
        return this.a + 1
      },
      set: function (v) {
        this.a = v - 1
      }
    }
  }
})
vm.aPlus   // => 2
vm.aPlus = 3
vm.a       // => 2
vm.aDouble // => 4

filter 过滤器

计算属性和过滤器都是用来对数据进行相关的修改的方法。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式。

严格来说,过滤器是计算属性的简化模式,运算比较简单的使用过滤器,比较复杂的则使用计算属性。

// HTML
<div id="app">
	<p>原始数字:{{num}}</p>    // 展示原始数字
	<p>修改后的数字:{{num | currencyFilter}}</p>  // 展示修改后的数字
        // 过滤器的调用方法是在变量后加上中隔线(|),在中隔线后加上过滤器的名字,
        // 这样过滤器就会自动把前面的数据作为参数添加进去。
</div>

// JS
var vm = new Vue({
	el:'#app',
	data:{
		num:100
	},
        // 过滤器
	filters:{
		currencyFilter:function(num){    // 过滤器名称及参数值
			return num * 10;  // 1000    // 返回处理后的结果
		}
	}
});

[ 过滤器 & 计算属性 & 方法 ] 新建方法和计算属性没有多大的差别,重点在于调用。

与计算属性相比,过滤器可以在多个地方使用,不像计算属性那样只能处理同样的数据;

与方法相比,过滤器的调用更加简洁。如,当需要多个过滤器处理数据时:

{{ message | filterA | filterB }}    // 使用过滤器处理数据,过滤器可以串联
{{ filterB(filterA(message)) }}    // 使用方法处理数据

methods 方法

methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。

类型:{ [key: string]: Function }
写法:不应该使用箭头函数来定义 method 函数
methods:{
	add:function{
		// 函数体
		console.log(this.msg);
	}
}
或
methods:{
	add(){
		// 需说明的是,this 指向 vm 实例
		// 因此,可以直接使用 this.数据名 访问 data 选项中的数据
	}
}

// 方法中的 this自动绑定为 Vue 实例。

var vm = new Vue({
  data: { a: 1 },
  methods: {
    plus: function () {
      this.a++
    }
  }
})
vm.plus()
vm.a // 2

[ 计算属性 - 依赖缓存 vs methods - 重新渲染 ] 对于最终的结果,两种方式确实是相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。

这就意味着只要依赖的响应式属性还没有发生改变,多次访问,计算属性会立即返回之前的计算结果,而不必再次执行函数。相比而言,只要发生重新渲染,method 调用总会执行该函数。

我们为什么需要缓存?

假设有一个重要的计算属性 A,这个计算属性需要一个巨大的数组遍历和做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 的 getter !

如果你不希望有缓存,请用 method 替代。


watch 监听器

类型:{ [key: string]: string | Function | Object | Array }
代码示例(承 - 计算属性):
watch:{
	// 键是“要观察的数据”,值是对应回调函数,其参数为新值和旧值。
	name:function(val,oldVal){
		// 函数体
	}
}
或
watch:{
	name(val,oldVal){
		console.log('name值发生了变化,新值为'+ val + ',旧值为' + oldVal);  // name值发生了变化,新值为World,旧值为Hello
	}
}
// 不应该对watch使用箭头函数

Vue 提供了一种通用的方式来观察和响应 Vue 实例上的数据变动:watch 属性。watch 属性,是一个对象,键是需要观察的表达式,值是对应回调函数,其参数为新值和旧值。值也可以是方法名,或者包含选项的对象。

Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: {
      f: {
        g: 5
      }
    }
  },
  watch: {
    a: function (val, oldVal) {
      console.log('new: %s, old: %s', val, oldVal)
    },
    // 方法名
    b: 'someMethod',
    // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
    c: {
      handler: function (val, oldVal) { /* ... */ },
      deep: true
    },
    // 该回调将会在侦听开始之后被立即调用
    d: {
      handler: 'someMethod',
      immediate: true
    },
    e: [
      'handle1',
      function handle2 (val, oldVal) { /* ... */ },
      {
        handler: function handle3 (val, oldVal) { /* ... */ },
        /* ... */
      }
    ],
    // watch vm.e.f's value: {g: 5}
    'e.f': function (val, oldVal) { /* ... */ }
  }
})
vm.a = 2 // => new: 2, old: 1

props

类型:Array<String> | Object

props 可以是数组或对象,用于接收来自父组件的数据。

props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

可以基于对象的语法使用以下选项:

  • type: 可以是下列原生构造函数中的一种:String、Number、Boolean、Ar ra y、Object、Da te、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定类型,否则抛出警告。
  • default: any   为该 prop 指定一个默认值。

如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。

  • required: Boolean 定义该 prop 是否是必填项。

在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。

  • validator: Function自定义验证函数会将该 prop 的值作为唯一的参数代入。

在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出。

// 简单语法
Vue.component('props-demo-simple', {
  props: ['size', 'myMessage']
})

// 对象语法,提供验证
Vue.component('props-demo-advanced', {
  props: {
    // 检测类型
    height: Number,
    // 检测类型 + 其他验证
    age: {
      type: Number,
      default: 0,
      required: true,
      validator: function (value) {
        return value >= 0
      }
    }
  }
})

[ propsData ]                            // 创建实例时传递 props。主要作用是方便测试。

类型:{ [key: string]: any }

限制:只用于 new 创建的实例中。
var Comp = Vue.extend({
  props: ['msg'],
  template: '<div>{{ msg }}</div>'
})

var vm = new Comp({
  propsData: {
    msg: 'hello'
  }
})

 

 

 

一般地,当模板内容较简单时,使用 data 选项配合表达式即可。

涉及到复杂逻辑时,需用到 computed、methods、watch 等选项,具体见 Vue 实例(选项及生命周期)?!

计算属性 computed

模板中绑定表达式非常的便利,但设计它们的初衷是用于简单运算。在模板中放入太多的逻辑会让模板过重且难以维护。

// 例如:

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

在这种情况下,模板不再简单和清晰。你必须看一段时间才能意识到,这里是想要显示变量 message的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。

所以,对于任何复杂逻辑,应当使用计算属性

你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage依赖于 vm.message,因此当 vm.message发生改变时,依赖于 vm.reversedMessage的绑定也会更新。而且,最妙的是我们是声明式地创建这种依赖关系:计算属性的 getter 是干净无副作用的,因此也是易于测试和理解的。


<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

侦听器 watch

Vue.js 提供了一个方法 $watch,它用于观察 Vue 实例上的数据变动。

[ 计算属性 vs 选项 - watch ] 当一些数据需要根据其它数据变化时, $watch很诱人。

不过,通常更好的办法是使用计算属性,而不是一个命令式的 $watch回调。

<div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

上述代码是命令式的和重复的,与计算属性对比(这样不是更好吗?):

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

[ 观察 Warchers ] 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher 。

[ vm.$watch API?!] 这是为什么 Vue 提供一个更通用的方法通过 watch选项,来响应数据的变化。

当你想要在数据变化响应时,执行异步操作或昂贵操作时,这是很有用的。

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>

在这个示例中,使用 watch选项允许我们执行异步操作(访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态,这些都是计算属性无法做到的。