渐进式 JavaScript 框架——Vue

Vue 作为一款优秀的前端框架,火了有很久一阵了。前两天给一个开源的 Chrome 插件 划词翻译 提了个 PR,才发现是时候学一波前端了,此文便记录 Vue 框架学习过程中一些笔记。

1. 渲染


v-if 和 v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

v-for

v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引:

1
<li v-for="(item, index) in items">

也可以用 of 替代 in 作为分隔符;

也可以用 v-for 通过一个对象的属性来迭代, 也可以提供键名、索引:

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

数组更新检测

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

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

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

1
2
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
1
2
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

为了解决第二类问题,你可以使用 splice

1
example1.items.splice(newLength)

对象更改检测注意事项

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除

v-for 和 v-if 共存

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,如下:

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

2. 事件


监听事件

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

有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:

1
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>

按键修饰符

在监听键盘事件时,我们经常需要检查常见的键值。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

1
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

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

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

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

3.绑定


语法糖

1
<input v-model="something">

这不过是以下示例的语法糖:

1
<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">

值绑定

对于单选按钮,勾选框及选择列表选项,v-model 绑定的 value 通常是静态字符串 (对于勾选框 radio 是逻辑值)

修饰符

.lazy

在默认情况下,v-modelinput 事件中同步输入框的值与数据 (除了 上述 IME 部分),但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

1
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为 Number 类型 (如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 numberv-model 来处理输入值:

1
<input v-model.number="age" type="number">

这通常很有用,因为在 type="number" 时 HTML 中输入的值也总是会返回字符串类型。

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

1
<input v-model.trim="msg">

4. 组件


组件组合

在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。

prop 向下传递,事件向上传递

每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。

命名

HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 需要转换为相对应的 kebab-case (短横线分隔式命名):

1
2
3
4
5
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
1
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>

如果你使用字符串模板,则没有这些限制。

绑定自定义事件

每个 Vue 实例都实现了事件接口,即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件