Vue.js基础拾遗

4,042 阅读9分钟

模版语法

插值

1、Vue.js的数据绑定形式是使用“Mustache”语法(双大括号)的形式,针对Html代码,需要使用v-html指令。

<p>Using v-html directive: <span v-html="rawHtml"></span></p>

2、Mustache语法不能作用在HTML特性上面,此时需要使用v-bind指令。

<div v-bind:id="dynamicId"></div>

指令

1、一些指令能够接收一个“参数”,在指令名称之后以冒号表示,如v-bind

<a v-bind:href="url">...</a>

2、从2.6.0开始,可以用方括号扩起来的Javascript表达式作为一个指令的参数

<a v-bind:[attributeName]='url'>...</a>

这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data 属性 attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href。

同样,我们可以使用动态参数为一个动态的事件名绑定处理函数

<a v-on:[eventName]="doSomething"> ... </a>

动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。 动态参数表达式有一些语法约束,因为某些字符,例如空格和引号,放在 HTML 特性名里是无效的。

3、修饰符(modifier)是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。如.prevent修饰符告诉v-on指令对于触发的事件调用event.prevent

<form v-on:submit.prevent="onSubmit">...</form>

4、指令简写

v-bind指令

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

v-on指令

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

计算属性与侦听器

计算属性是和普通属性一样在模版中绑定的,只不过该属性的值涉及到一系列的计算,并不是单纯的一个属性值。

计算属性的getter函数是没有副作用(side effect)的。

计算属性VS方法

我们可以将同一个函数定义为一个方法而不是一个计算属性,两种方式的最终结果是相同的。不同的是计算属性是基于他们的依赖进行缓存的。当相关依赖不变的情况下,计算属性是直接获取缓存的结果,不需要执行函数,而方法的写法每当重新渲染时,都会被再次执行。

计算属性VS侦听属性

Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变更:侦听属性,通过watch来监听属性的变化。但是通常更好的做法是使用计算属性而不是命令式的watch回调。

那么什么时候选择侦听属性更好呢?

当响应数据变化的处理是执行异步或者开销较大的操作时,使用侦听属性是有用的。

Class与Style绑定

v-bind用于classstyle时,Vue.js做了专门的增强,表达式结果的类型除了字符串之外,还可以是对象或数组。

绑定HTML Class

1、v-bind:class指令可以与普通的class属性共存。我们也可以绑定一个返回对象的计算属性,这是非常有用的模式。

2、我们可以把一个数组传给v-bind:class,以应用一个class列表。

3、当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。

绑定内联样式

1、v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名.

2、直接绑定到一个样式对象通常更好,这会让模板更清晰:

3、对象语法常常结合返回对象的计算属性使用

4、当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

5、可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值。这样只会渲染数组中最后一个被浏览器支持的值。

条件渲染

1、v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。也可以用 v-else 添加一个“else 块”。v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

2、在 <template> 元素上使用 v-if 条件渲染分组

3、通过添加一个具有唯一值的 key 属性来表达“两个元素是完全独立的,不要复用他们”。

4、带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display

v-if & v-show

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

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

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

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

5、当 v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级。

列表渲染

1、v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。

2、可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法, v-for="item of items"

3、可以用v-for来迭代一个对象的属性。v-for="(value, key) in object"

在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。

4、为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的唯一 id

不要使用对象或数组之类的非原始类型值作为 v-for 的 key。用字符串或数类型的值取而代之。

5、由于Javascript的限制,Vue不能检测到下面的变动情况:

  • 当利用索引直接设置一个项目时,不会触发状态更新。可以通过下面方式实现:
// 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)
  • 当直接修改数组长度时,不会触发状态更新。可以通过下面方式实现:
vm.items.splice(newLength)

6、Vue 不能检测对象属性的添加或删除

对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性

7、需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。

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

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

8、显示过滤/排序结果,可以通过创建返回过滤或排序数组的计算属性来实现。在计算属性不适用的情况下(如嵌套v-for循环中)可以适用method方法来处理。

9、v-for & v-if

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。

10、在自定义组件里,你可以像任何普通元素一样用 v-for

2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。

然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props

// 一个完整的todolist demo
<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Add a todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed the cat"
    >
    <button>Add</button>
  </form>
  <ul>
    <li
      is="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>

Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Do the dishes',
      },
      {
        id: 2,
        title: 'Take out the trash',
      },
      {
        id: 3,
        title: 'Mow the lawn'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})

事件处理

事件修饰符

  • .stop
  • .prevent
  • .capture
  • .self
<!-- 阻止单击事件继续传播 -->
<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 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

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

不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。

  • .passive(2.3.0 new)
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>  // 2.3.0 new

.passive 修饰符尤其能够提升移动端的性能

不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

按键修饰符

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

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

Vue提供了常用的按键码的别名

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

系统修饰键(2.1.0 new)

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。

  • .ctrl
  • .alt
  • .shift
  • .meta

请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode:keyup.17。

.exact修饰符(2.5.0 new)

.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

鼠标按钮修饰符(2.2.0 new)

  • .left
  • .right
  • .middle

这些修饰符会限制处理函数仅响应特定的鼠标按钮。

表单输入绑定

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部使用不同的属性为不同的输入元素并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

修饰符

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

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

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim

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

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

组件基础

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

1、data必须是函数

一个组件的data选项必须是一个函数,因此每个实例才可以维护一份被返回对象的独立的拷贝。

2、组件有两种注册类型:全局注册局部注册。我们的组件都只是通过Vue.component全局注册的

Vue.component('my-component-name', {
  // ... options ...
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

3、通过Prop向子组件传递数据

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。

4、每个组件必须只有一个根元素

5、父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件,同时子组件可以通过调用内建的 $emit 方法 并传入事件名称来触发一个事件:

<parentElement 
  ...
  v-on:special-event="todo something..."></parentElement>

<childElement v-on:click="$emit('special-event')">
  Click to trigger special-enent
</childElement>

插槽

Vue自定义的<slot>元素可以实现通过插槽分发内容。

解析DOM时的注意事项

HTML元素有些会有严格的限制包含和被包含的关系,这会导致我们使用一些有约束条件的元素时会遇到一些问题。此时可以通过is特性来解决

<table>
  <tr is="blog-post-row"></tr>
</table>

下面情况不会出现限制:

  • 字符串模版(例如 template:‘...’)
  • 单文件组件(.vue)
  • <script type="text/x-template">

小结

以上是在重温Vue.js官方文档基础部分内容时做出的拾遗笔记,记录认为是一些需要特别注意的地方。后续会继续深入进行Vue.js的学习。