VUE2中文文档:语法基础笔记

声明式渲染

Vue.js 的核心是,可以采用简洁的模板语法来声明式的将数据渲染为 DOM:

<div id="app">
  {{ message }}         //模板语法
</div>

  

var app = new Vue({  //新建vue实例(响应式)
  el: '#app',      //挂载到#app
  data: {
    message: 'Hello Vue!'  //数据
  }
})

 

除了文本插值(text interpolation),我们还可以采用这样的方式绑定 DOM 元素属性:

<div id="app-2">
  <span v-bind:title="message">     //v-bind:属性=“数据”
    鼠标悬停此处几秒,
    可以看到此处动态绑定的 title!
  </span>
</div>

 

 

var app2 = new Vue({
  el: '#app-2',
  data: {
    message: '页面加载于 ' + new Date().toLocaleString()
  }
})  

 

由组件组合而成的应用程序

在 Vue 中,一个组件本质上是一个被预先定义选项的 Vue 实例,在 Vue 中注册组件很简单:

// 定义一个被命名为 todo-item 的新组件
Vue.component('todo-item', {
  template: '<li>这是一个 todo 项</li>'
})

现在你可以在另一个组件模板中组合使用它:

<ol>
  <!-- 创建一个 todo-item 组件的实例 -->
  <todo-item></todo-item>
</ol>

将数据从父作用域传到子组件。让我们来修改下组件的定义,使它可以接受一个 prop

var app7 = new Vue({                 //vue实例挂载到app-7
  el: '#app-7',
  data: {
    groceryList: [
      { id: 0, text: '蔬菜' },
      { id: 1, text: '奶酪' },
      { id: 2, text: '其他人类食物' }
    ]
  }
})

<div id="app-7">                    //组件模板app-7             <ol> <!-- 现在我们为每个 todo-item 提供了 todo 对象, 其中它的内容是动态的。 我们还需要为每个组件提供一个 "key", 这将在之后详细解释。 --> <todo-item v-for="item in groceryList" v-bind:todo="item"               //将遍历的每个item对象传递给todo v-bind:key="item.id">             //由于vue对组件渲染是可复用的,如果不给每一个添加不同的key,后面循环的组件不会重新渲染  </todo-item>                    //而是直接复用第一次渲染的结果 </ol> </div>



Vue.component('todo-item', { props: ['todo'],                 //子组件用props接受todo template: '<li>{{ todo.text }}</li>'     //子组件模板 })

 

下面正式开始:

Vue 实例

var vm = new Vue({    //创建
  // 选项
})

 

Vue 应用程序由「一个使用 new Vue 创建的 Vue 根实例」、「嵌套的树结构(可选)」和「可复用的组件」组成。

data 和 methods

在创建 Vue 实例时,会将所有在 data 对象中找到的属性,都添加到 Vue 的响应式系统中。每当这些属性的值发生变化时,视图都会“及时响应”,并更新相应的新值。

每当 data 对象发生变化,都会触发视图重新渲染。值得注意的是,如果实例已经创建,那么只有那些 data 中的原本就已经存在的属性,才是响应式的。也就是说,如果在实例创建之后,添加一个新的属性,

例如:vm.b = ' hide';

然后,修改 b 不会触发任何视图更新。如果你已经提前知道,之后将会用到一个开始是空的或不存在的属性,你需要预先设置一些初始值。例如:

data: {
  newTodoText: '',
  visitCount: 0,
  hideCompletedTodos: false,
  todos: [],
  error: null
}

唯一的例外是,使用 Object.freeze() 来防止已有属性被修改,这也意味着响应式系统无法追踪变化。

 

除了 data 属性, Vue 实例还暴露了一些有用的实例属性和方法。这些属性与方法都具有前缀 $,以便与用户定义(user-defined)的属性有所区分。例如:

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})

vm.$data === data                           // => true      实例属性,获取实例data
vm.$el === document.getElementById('example')         // => true    获取挂载的DOM对象

// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
  // 此回调函数将在 `vm.a` 改变后调用
})

 

 点击API文档,来获取实例属性(instance property)和方法(methods)的完整列表。

 

实例生命周期钩子函数

每个 Vue 实例在被创建之前,都要经过一系列的初始化过程 - 例如:

 

Vue 实例需要设置数据观察(set up data observation)、

编译模板(compile the template)、

在 DOM 挂载实例(mount the instance to the DOM),

数据变化时更新 DOM(update the DOM when data change)。

 

在这个过程中,Vue 实例还会调用执行一些生命周期钩子函数,这样用户能够在特定阶段添加自己的代码。

生命周期示意图

模板语法

所有 Vue.js 的模板都是有效的 HTML,能够被遵循规范的浏览器和 HTML 解析器解析。

在底层的实现上,Vue 将模板编译为可以生成 Virtual DOM 的 render 函数。结合响应式系统,在应用程序状态改变时,Vue 能够智能地找出重新渲染的最小数量的组件,并应用最少量的 DOM 操作。

如果你熟悉虚拟 DOM 的概念,并且倾向于使用原生 JavaScript,还可以不使用模板,而是直接编写 render 函数,具备可选的 JSX 语法支持。

 

 

插值(Interpolations)

文本(Text)

 使用 “mustache” 语法(双花括号)的文本插值(text interpolation),也可以通过使用 v-once 指令,执行一次性插值,也就是说,在数据改变时,插值内容不会随之更新。但是请牢记,这也将影响到同一节点上的其他所有绑定。

原始 HTML(Raw HTML)        (不建议使用)

属性(Attributes)

使用 JavaScript 表达式

有个限制是,每个绑定都只能包含单个表达式。

 

computed 属性和 watcher

你可以像绑定普通属性一样,将 computed 属性的数据,绑定(data-bind)到模板中的表达式上。Vue 能够意识到 computed属性依赖于 实例的数据,也会在 示例数据修改后,更新所有依赖于 computed属性 的数据绑定。最恰到好处的部分是,我们是通过声明式来创建这种依赖关系:computed 属性的 getter 函数并无副作用(side effect),因此也更加易于测试和理解。

 

computed 缓存 vs method 方法

computed 属性会基于它所依赖的数据进行缓存。每个 computed 属性,只有在它所依赖的数据发生变化时,才会重新取值(re-evaluate)。这就意味着,只要 computed属性函数依赖的实例数据 没有发生变化,多次访问 computed 属性,将会立刻返回之前计算过的结果,而不必每次都重新执行函数。

为什么我们需要将依赖数据缓存起来?假设一种场景,我们有一个高性能开销(expensive)的 computed 属性 A,在 computed 属性的 getter 函数内部,需要遍历循环一个巨大数组,并进行大量计算。然后还有其他 computed 属性直接或间接依赖于 A。如果没有缓存,我们将不可避免地多次执行 A 的 getter 函数,这远多余实际需要执行的次数!然而在某些场景下,你可能不希望有缓存,请使用 method 方法替代。

 

computed 属性和 watch 属性

更推荐的方式是,使用 computed 属性,而不是命令式(imperative)的 watch 回调函数。例如:

computed版本

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName           //需要一个返回值加入到实例数据或者修改实例数据
    }                                     //computed属性会检测其依赖的实例数据       
  }
})

 

 watch版本

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'                //watch属性,检测已经存在的属性数据,不会自动返回为新实例属性数据,所以要先声明 
  },
  watch: {
    firstName: function (val) {                 //观测发生改变的属性对象,而不观测其依赖的实例数据,所以需要分为两个函数实现功能。 
      this.fullName = val + ' ' + this.lastName       
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

 

 对比 computed 属性实现的版本,以上代码是命令式和重复的。

 

computed 属性中设置 setter

computed 属性默认只设置 getter 函数,不过在需要时,还可以提供 setter 函数:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
computed: {
  fullName: {
    // getter 函数
    get: function () {                  //get函数观测对象依赖,并返回变化
      return this.firstName + ' ' + this.lastName
    },
    // setter 函数
    set: function (newValue) {            //set函数观测对象让你可以在computed中更改对象依赖的数据    
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
})

 

 现在当你运行 vm.fullName = 'John Doe',将会调用 setter,然后会对应更新 vm.firstName 和 vm.lastName

 

watcher

虽然在大多数情况下,更适合使用 computed 属性,然而有些时候,还是需要一个自定义 watcher。当你需要在数据变化响应时,执行异步操作,或高性能消耗的操作,自定义 watcher 的方式就会很有帮助。

<div id="watch-example">
  <p>
    问一个答案是 yes/no 的问题:
    <input v-model="question">          //v-modle会将input输入值传给question
  </p>
  <p>{{ answer }}</p>
</div>
<!-- 对于 ajax 库(ajax libraries)和通用工具方法的集合(collections of general-purpose utility methods)来说, -->
<!-- 由于已经存在大量与其相关的生态系统, -->
<!-- 这也可以使你自由随意地选择自己最熟悉的。 -->
<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: '你要先提出问题,我才能给你答案!'
  },
  watch: {     //这种需求,不是更新观测对象(computed.get)或者更新其依赖(computed.set), 而是观测变化去做与数据无关的操作,computed无法实现       
    // 只要 question 发生改变,此函数就会执行              
    question: function (newQuestion, oldQuestion) {    //不是很懂两个参数,但我想可能这是watch能监测到的改变之前和之后的对象,
      this.answer = '等待输入停止……'
      this.getAnswer()
    }
  },
  methods: {
    // _.debounce 是由 lodash 提供的函数,
    // 在运行特别消耗性能的操作时,
    // 可以使用 _.debounce 来限制频率。
    // 在下面这种场景中,我们需要限制访问 yesno.wtf/api 的频率,
    // 等到用户输入完毕之后,ajax 请求才会发出。
    getAnswer: _.debounce(
      function () {
        if (this.question.indexOf('?') === -1) {
          this.answer = '问题通常需要包含一个中文问号。;-)'
          return
        }
        this.answer = '思考中……'
        var vm = this                    //ajax请求中的this可能没有指向实例,所以在请求之前先把实例对象this赋值给变量vm
        axios.get('https://yesno.wtf/api')
          .then(function (response) {
            vm.answer = _.capitalize(response.data.answer)
          })
          .catch(function (error) {
            vm.answer = '错误!API 无法处理。' + error
          })
      },
      // 这是用户停止输入操作后所等待的毫秒数。
      // (译者注:500毫秒之内,用户继续输入,则重新计时)
      500
    )
  }
})
</script>

 

class 和 style 绑定

与 HTML 的 class 绑定(Binding HTML Classes)

(内联、外部引用)这两种方式的渲染结果相同。我们还可以将 class 和 style 与某个 computed 属性绑定在一起,此 computed 属性所对应的 getter 函数需要返回一个对象。这是一种常用且强大的用法

<div v-bind:class="classObject"></div>    //简写 :class="classObject" 
data: {
  isActive: true,
  error: null
},
computed: {                       //通过computed属性控制classObjecr对其它class的影响
  classObject: function () {                     //如果classObject属性去除了,先前computed return的样式会恢复吗?
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

 

我们可以向 v-bind:class 传入一个数组,来与 class 列表对应:

<div v-bind:class="[activeClass, errorClass]"></div>

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> 
//这里会直接添加 errorClass,但是只有在 isActive 值是 truthy 时,才会添加 activeClass

<div v-bind:class="[{ active: isActive }, errorClass]"></div>  //这里使用对象语法比三元运算更加简洁
 

 

在组件中使用

 当你在自定义组件中使用 class 属性,这些 class 会被添加到组件的根元素上。根元素上已经存在的 class 不会被覆盖。

 

 

与内联 style 绑定(Binding Inline Styles)

 

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

v-bind:style 的对象语法,通常也会和 computed 属性结合使用,此 computed 属性所对应的 getter 函数需要返回一个对象。

 

<div v-bind:style="[baseStyles, overridingStyles]"></div>

 

从 2.3.0+ 起,你可以为每个 style 属性提供一个含有多个(前缀)值的数组,例如:

<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

 

根据条件进行渲染

 v-else 元素必须紧跟在 v-if 或 v-else-if 元素之后 - 否则无法识别它。

使用 key 控制元素是否可复用

Vue 会尽可能高效地渲染元素,通常会复用已渲染元素,而不是从头重新渲染。这样的实现方式,除了有助于使 Vue 变得非常快之外,还具有一些额外的优势。

但是这样有时并不符合实际需求,所以 Vue 为如下所述的情况提供了一种方式:“这两个元素是完全独立的 - 请不要复用它们”。那就是为它们添加一个具有不同值的 key 属性。

具有 v-show 的元素会始终渲染并保留在 DOM 中。v-show 只会切换元素的 display 这个 CSS 属性。

v-if 是“真实”的条件渲染,因为它会确保条件块(conditional block)在切换的过程中,完整地销毁(destroy)和重新创建(re-create)条件块内的事件监听器和子组件。

v-if 是惰性的(lazy):如果在初始渲染时条件为 false,它不会执行任何操作 - 在条件第一次变为 true 时,才开始渲染条件块。

通常来说,v-if 在切换时有更高的性能开销,而 v-show 在初始渲染时有更高的性能开销。因此,如果需要频繁切换,推荐使用 v-show,如果条件在运行时改变的可能性较少,推荐使用 v-if

 

列表渲染

使用 v-for 遍历数组生成元素

在 v-for 代码块中,我们可以完全地访问父级作用域下的属性。v-for 还支持可选的第二个参数,作为当前项的索引。

使用 v-for 遍历对象

还可以提供第二个参数,作为对象的键名(key,然后第三个参数作为索引(index):

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>

遍历一个对象时,是按照 Object.keys() 得出 key 的枚举顺序来遍历,无法保证在所有 JavaScript 引擎实现中完全一致。

推荐,在使用 v-for 时,尽可能提供一个 key,除非迭代的 DOM 内容足够简单,或者你是故意依赖于默认行为来获得性能提升。

数组变化检测(Array Change Detection)

变化数组方法(Mutation Methods)

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换一个数组(Replacing an Array)

例如 filter()concat() 和 slice()

你可能会认为这将导致 Vue 丢弃现有 DOM 并重新渲染(re-render)整个列表 - 幸运的是,情况并非如此。Vue 实现了一些智能启发式方法(smart heuristic)来最大化 DOM 元素重用(reuse),因此将一个数组替换为包含重叠对象的另一个数组,会是一种非常高效的操作。

 

注意事项(Caveats)

由于 JavaScript 的限制,Vue 无法检测到以下数组变动:

  1. 当你使用索引直接设置一项时,例如 vm.items[indexOfItem] = newValue
  2. 当你修改数组长度时,例如 vm.items.length = newLength

为了解决第 1 个问题,以下方式都可以实现相同的效果,但是却可以通过响应式系统出发状态更新:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

//你还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
vm.$set(vm.items, indexOfItem, newValue)

为了解决第 2 个问题,你可以使用 splice

vm.items.splice(newLength)

 

有时,你想要向已经存在的对象上添加一些新的属性,例如使用 Object.assign() 或 _.extend() 方法。在这种情况下,应该创建一个新的对象,这个对象同时具有两个对象的所有属性,因此,改为:                    //不是很理解

Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

//可以通过如下方式,添加新的响应式属性:
vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

 

显示过滤/排序结果(Displaying Filtered/Sorted Results)

有时,我们想要显示一个数组过滤或排序后(filtered or sorted)的副本,而不是实际改变或重置原始数据。在这种情况下,可以创建一个返回过滤或排序数组的计算属性。

<li v-for="n in evenNumbers">{{ n }}</li>

data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } }

在计算属性不适用的情况下(例如,在嵌套的 v-for 循环内),可以使用一个 method 方法:  //不是很理解红色部分,参考上面循环,思考如果外部再套一层循环的computed结果

 

data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

使用 v-for 在整数值范围内迭代

<div>
  <span v-for="n in 10">{{ n }}</span>
</div>

带有 v-if 的 v-for

当它们都处于同一节点时,v-for 的优先级高于 v-if。这意味着,v-if 将分别在循环中的每次迭代上运行。当你只想将某些项渲染为节点时,这会非常有用,如下:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

如果你的意图与此相反,是根据条件跳过执行循环,可以将 v-if 放置于包裹元素上(或放置于 <template> 上)。例如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

使用 v-for 遍历组件

现在,在 2.2.0+ 版本,当对组件使用 v-for 时,必须设置 key 属性。

无法自动向组件中传入数据,这是因为组件有自己的独立作用域。为了将组件外部的迭代数据传入组件,我们还需要额外使用 props:

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>

没有通过 v-for 将 item 自动注入到组件中的原因是,一旦自动注入,就会使得组件与 v-for 指令的运行方式紧密耦合(tightly coupled)在一起。通过显式声明组件数据来源,可以使得组件可重用于其他场景。

<div id="todo-list-example">
  <input
    v-model="newTodoText"
    v-on:keyup.enter="addNewTodo"
    placeholder="Add a todo"
  >
  <ul>
    <li
      is="todo-item"       //注意 is="todo-item" 属性。这在 DOM 模板中是必需的,因为在 <ul> 中,只有 <li> 是有效元素。这与调用 <todo-item> 的实际结果相同,但是却可以解决浏览器潜在的解析错误
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>

 

 

事件处理

监听事件

 我们可以使用 v-on 指令监听 DOM 事件,并在事件被触发时执行一些 JavaScript 代码。

由于许多事件处理器的逻辑很复杂,所以把 JavaScript 代码都保存在 v-on 属性的值中是不可行的做法。这就是为什么 v-on 还可以接收要调用的方法名。

行内语句的事件处理器中,有时我们也需要访问原始 DOM 事件对象。可以使用特殊的 $event 变量将它传递给一个方法:

<button v-on:click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>
// ...
methods: {
  warn: function (message, event) {
    // 现在,我们可以访问原始事件对象
    if (event) event.preventDefault()
    alert(message)
  }
}

事件修饰符(Event Modifiers)

尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

Vue.js 为 v-on 提供了事件修饰符。回想一下,修饰符是以点(.)开头的指令后缀来表示。

<!-- 停止点击事件冒泡 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重新载入页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以链式调用 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时,使用事件捕获模式 -->
<!-- 也就是说,内部元素触发的事件先在此处处理,然后才交给内部元素进行处理 -->        //想不到实际运用场景
<div v-on:click.capture="doThis">...</div>

<!-- 只有在 event.target 是元素自身时,才触发处理函数。 -->
<!-- 也就是说,event.target 是子元素时,不触发处理函数 -->
<div v-on:click.self="doThat">...</div>

<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>



<!-- 滚动事件的默认行为(滚动)将立即发生, -->
<!-- 而不是等待 `onScroll` 完成后才发生, -->
<!-- 以防在滚动事件的处理程序中含有 `event.preventDefault()` 调用 -->
<div v-on:scroll.passive="onScroll">...</div>
                   //.passive 修饰符对于提高移动设备的性能尤其有用。       

使用修饰符时的顺序会产生一些影响,因为相关的代码会以相同的顺序生成。所以,使用 v-on:click.prevent.self 会阻止所有点击,而 v-on:click.self.prevent 只阻止元素自身的点击。

不要将 .passive 和 .prevent 放在一起使用,因为 .prevent 将被忽略,并且浏览器可能会显示一条警告。记住,.passive 会向浏览器传达的意思是,你并不希望阻止事件的默认行为。

按键修饰符(Key Modifiers)

<!-- 和上面的示例相同 -->
<input v-on:keyup.enter="submit">

<!-- 也可用于简写语法 -->
<input @keyup.enter="submit">

这里列出所有的按键修饰符别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

还可以自定义按键修饰符别名,通过全局 config.keyCodes 对象设置:

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

自动对应按键修饰符(Automatic Key Modifers)

也可以直接使用 KeyboardEvent.key 暴露出来的所有合法按键名作为修饰符,但是要将它们转换为串联式命名(kebab-case):

<input @keyup.page-down="onPageDown">

系统辅助按键(System Modifier Keys)

仅在以下修饰符对应的按键被按下时,才会触发鼠标或键盘事件监听器:

  • .ctrl
  • .alt
  • .shift
  • .meta
<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">做一些操作</div>

 

.exact 修饰符(.exact Modifier)

.exact 修饰符可以控制触发事件所需的系统辅助按键的准确组合。

<!-- 如果 Alt 键或 Shift 键与  Ctrl 键同时按下,也会触发事件 -->
<button @click.ctrl="onClick">A</button>

<!-- 只在 Ctrl 按键按下,其他按键未按下时,触发事件 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 只在系统辅助按键按下时,触发事件 -->
<button @click.exact="onClick">A</button>

鼠标按键修饰符(Mouse Button Modifiers)

  • .left
  • .right
  • .middle

这些修饰符会限制处理函数,仅响应特定的鼠标按键触发的事件。

 

表单 input 绑定

可以通过使用 v-model 指令,在表单 input 和 textarea 元素上创建双向数据绑定。v-model 指令可以根据 input 的 type 类型,自动地以正确的方式更新元素。虽然略显神奇,然而本质上 v-model 不过是「通过监听用户的 input 事件来更新数据」的语法糖,以及对一些边界情况做特殊处理。

v-model 会忽略所有表单元素中 valuechecked 或 selected 属性上初始设置的值,而总是将 Vue 实例中的 data 作为真实数据来源。因此你应该在 JavaScript 端的组件 data 选项中声明这些初始值,而不是 HTML 端。

 

与 value 属性绑定(待补充)

修饰符(modifiers)

.lazy

默认情况下,v-model 会在每次 input 事件触发之后,将数据同步至 input 元素中(除了上述提到的输入法组合文字时不会)。可以添加 lazy 修饰符,从而转为在触发 change 事件后同步。

.number

如果想要将用户的输入,自动转换为 Number 类型(译注:如果转换结果为 NaN 则返回字符串类型的输入值),可以在 v-model 之后添加一个 number 修饰符,来处理输入值:


这通常很有用,因为即使是在 type="number" 时,HTML 中 input 元素也总是返回一个字符串类型的值。

.trim

如果想要将用户的输入,自动过滤掉首尾空格,可以在 v-model 之后添加一个 trim 修饰符,来处理输入值:

 

posted @ 2018-04-28 11:23  刁民阿准  阅读(1802)  评论(0编辑  收藏  举报