Vue 2.0 出来也有一段时间了,作为一个有志向的全面发展好青年,在征服 Vue 1.x,React,React Native 后,为了之后能更快迁移公司的项目到 Vue 2.x,于是决定先看看 Vue 2.0。

鉴于部分读者可能不了解 Vue,先简单看看各种特性。

本文假设你有一定的 HTML 基础,并熟悉一种或以上编程语言(那就能看懂 JS 了)。

模板语法

Vue 提供了一堆数据绑定语法。

  • {{ text }} 文本插值
  • {{{ raw_html }}} HTML 输出
  • v-bind HTML 属性插值。如
  • JavaScript 表达式。直接在 mustache、属性插值里面使用各种表达式(加减乘除、三元运算、方法调用等)。
  • 过滤器(有点类似 Shell 命令中的管道,可以定义过滤器来对原始值进行变化)。
  • 指令。之前提到的 v-bind 也是一种指定,其他包括 v-on: 系列(dom 事件的监听)、v-for、v-model等。

Vue 实例

Vue 实例,实则也就是 ViewModel(数据 + 函数),都是通过构造函数 Vue 创建的:

var data = { a: 1 } var vm = new Vue({  el: "#example",  data: data,  created: function () {  // `this` points to the vm instance  console.log("a is: " + this.a)  } }) vm.$data === data // -> true vm.$el === document.getElementById("example") // -> true // $watch is an instance method vm.$watch("a", function (newVal, oldVal) {  // this callback will be called when `vm.a` changes }) 

Vue 实例都有自己的生命周期,比如 created, mounted, updated 以及 destroyed。所有方法被 called 的时候,this 都指向所在的 Vue 实例。

Lifecycle 图如下:

计算属性和监听器

计算属性

其实就是一个需要计算的 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: {  // a computed getter  reversedMessage: function () {  // `this` points to the vm instance  return this.message.split("").reverse().join("")  }  } }) </div> 

和使用 method 的区别在于,计算属性根据它的依赖被缓存,即如果 message 没有被修改,下次 get 不会进行重复计算,而 method 则每次调用都会重新计算。这也意味着如 Date.now() 这样返回的计算属性会永远得不到更新。

Setter

默认情况下,计算属性只有一个 getter,我们也可以给它加上 setter:

 computed: {  fullName: {  // getter  get: function () {  return this.firstName + " " + this.lastName  },  // setter  set: function (newValue) {  var names = newValue.split(" ")  this.firstName = names[0]  this.lastName = names[names.length - 1]  }  } } 

如此,当我们调用 vm.fullName = "MarkZhai" 的时候,firstName 和 lastName 都会被更新。

监听器

Vue 的 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  }  } }) 

看上去好像简单了很多,那还要 Watcher 干啥呢。。。主要应用场景是异步或耗时操作:

<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js">script> <script src="https://unpkg.com/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: {  // whenever question changes, this function will run  question: function (newQuestion) {  this.answer = "Waiting for you to stop typing..."  this.getAnswer()  }  },  methods: {  // _.debounce is a function provided by lodash to limit how  // often a particularly expensive operation can be run.  // In this case, we want to limit how often we access  // yesno.wtf/api, waiting until the user has completely  // finished typing before making the ajax request. To learn  // more about the _.debounce function (and its cousin  // _.throttle), visit: https://lodash.com/docs#debounce  getAnswer: _.debounce(  function () {  var vm = this  if (this.question.indexOf("?") === -1) {  vm.answer = "Questions usually contain a question mark. ;-)"  return  }  vm.answer = "Thinking..."  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  })  },  // This is the number of milliseconds we wait for the  // user to stop typing.  500  )  } }) script> 

如此,使用 watch 让我们可以进行异步操作(访问 API),限制操作间隔,并设置中间状态直到获得了真正的答案。

除了使用 watch option,也可以用 vm.$watch API。

Class 和 Style 绑定

除了数据绑定,常见的还有 style、class 的绑定(正如很久以前在 JQuery 中常用的)。

对象语法

我们可以传递一个对象给 v-bind:class 来动态切换 classes:

<div class="static"  v-bind:class="{ active: isActive, "text-danger": hasError }"> div> 

对应的 active 和 text-danger 则通过 data 传递过来。

我们也可直接通过 data 把 class 传递过来

<div v-bind:class="classObject">div> 
data: {  classObject: {  active: true,  "text-danger": false  } } 

当然我们也能使用上面提到的 computed 来进行对应属性,如 active 的计算。

数组语法

可以直接传递一个数组给 v-bind:class:

<div v-bind:class="[activeClass, errorClass]"> 
data: {  activeClass: "active",  errorClass: "text-danger" } 

也可以写成

<div v-bind:class="[isActive ? activeClass : "", errorClass]"> <div v-bind:class="[{ active: isActive }, errorClass]"> 

绑定内联样式

跟 class 差不多:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + "px" }">div> 

或者直接绑定到 style:


		
			"styleObject">div>  data: {  styleObject: {  color: "red",  fontSize: "13px"  } } 
		

类似的,也有数组绑定。

条件绑定

v-if

其实就是个标签啦

<h1 v-if="ok">Yesh1>  <h1 v-if="ok">Yesh1> <h1 v-else>Noh1> 

因为 v-if 必须附加到一个单一 element 上,那如果我们想切换多个元素呢?可以使用 template 元素:

<template v-if="ok">  <h1>Titleh1>  <p>Paragraph 1p>  <p>Paragraph 2p> template> 

v-show

也可以用 v-show 来做条件显示的逻辑,

<h1 v-show="ok">Hello!h1>