Vue文档阅读——Vue基础

223 阅读15分钟

Vue实例

数据与方法

只有当实例被创建时就已经存在于data中的属性才是响应式的。

如果你新添加一个属性,那么此改动不会触发任何视图的更新。

唯一例外:Object.freeze()

将会阻止修改现有属性,响应系统无法追踪变化。

var obj = {
  foo: 'bar'
}

Object.freeze(obj)

new Vue({
  el: '#app',
  data: obj
})
<div id="app">
  <p>{{ foo }}</p>
  <!-- 这里的 `foo` 不会更新! -->
  <button v-on:click="foo = 'baz'">Change it</button>
</div>

Vue实例还暴露了一些有用的实例属性和方法。他们都有前缀$,用于和用户定义的属性区分开来。

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

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

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

实例生命周期钩子

不要在选项属性或回调上使用箭头函数。因为箭头函数并没有thisthis会作为变量一直向上级词法作用域查找,直到找到为止。

不能写:created:()=>{}vm.$watch('a',()=>{})

生命周期图

模板语法

插值

文本

Mustache语法{{ msg }}

也可配合v-once进行一次性的插值

<span v-once>这个将不会改变: {{ msg }}</span>

原始HTML

v-html指令

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

动态渲染的html可能会导致xss攻击(跨站脚本),请只对可信内容使用html插值。

Attribute属性

使用v-bind指令

<button v-bind:disabled="isButtonDisabled">Button</button>

如果isButtonDisabled的值是nullundefinedfalse,那么根本就不会有disabled这个属性。

使用JavaScript表达式

只能使用单个表达式,不能使用语句

指令Directives

参数

v-bindv-on ...

动态参数

可以用方括号括起来的JavaScript表达式作为一个指令的参数:

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

data中有attributeName这个属性,就会拿到方括号中

动态参数的值的约束

动态参数会预期求出一个字符串,异常情况下值为null。可显式地用于移除绑定。其他非字符串类型都会触发警告。

动态参数表达式的约束

  • 不能有空格或者引号
  • 最好不要用大写,因为会全部强制转换小写

修饰符

以.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。

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

告诉v-on指令对于触发的事件调用event.preventDefault()

缩写

:@

计算属性和侦听器

计算属性

模板内表达式如果放入太多逻辑会难以维护,应该使用计算属性。

<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('')
    }
  }
})

这里的计算属性reversedMessage将用作属性vm.reversedMessagegetter函数。

console.log(vm.reversedMessage) // => 'olleH'

计算属性缓存VS方法

我们同样可以在表达式中用方法达到一样的效果

<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时,它们才会重新求值。只要message不改变,多次访问reversedMessage就会立即返回原来的结果,而不用再次执行函数。

computed: {
  now: function () {
    return Date.now()
  }
}

所以now是不会改变的,因为Date.now()不依赖任何东西。

而方法就每次都会执行。

为了节省性能。

计算属性vs侦听属性

Vue还有一种更通用的方式观察和响应数据变动:侦听属性。

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

计算属性的setter

计算属性默认只有getter,不过你也可以自己提供一个

// ...
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 = 'William Duan',setter就会被调用,vm.firstNamevm.lastName也会相应更新。

侦听器

当需要数据变化时执行异步或者开销比较大的操作时,watch就有用了。

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
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
        })
    }
  }
})

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

除了watch还可以使用命令式的vm.$watch API

Class与Style绑定

绑定HTML Class

对象语法

可以传给v-bind:class一个对象,以动态切换class:

<div v-bind:class="{ active: isActive }"></div>

active这个class存在与否,将取决于数据属性isActive的boolean值。

可以将这个对象拿出来,放在data或者计算属性去。

data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    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>
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

如果想根据条件切换可以尝试三元表达式:

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

在数组语法中也可以用对象语法

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

用在组件上

在组件上同样适用

绑定内联样式

对象语法

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

同样可以拿到data或者用返回对象的计算属性。

数组语法

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

自动添加前缀

使用v-bind:style时,会自动添加浏览器引擎前缀。

多重值

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

只会渲染数组中最后一个浏览器支持的值。

条件渲染

v-if

用于条件性地渲染一块内容,只会在指令的表达式返回truthy值的时候被渲染。

也可以用v-else添加一个else块

在template上使用v-if条件渲染分组

因为v-if是一个指令,所以必须将它添加到元素上。要切换多个元素:

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

v-else

v-else必须紧跟在v-if或者v-else-if后面,否则不会被识别。

v-else-if

用key管理可复用的元素

Vue会复用已有元素而不是从头开始渲染。如果你允许用户在不同的登录方式之间切换:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

上面切换loginType将不会清除用户已经输入的内容,因为两个模板使用了相同的元素,input不会被替换,而仅仅替换了placeholder

Vue还提供一种方式表达这两个元素是完全独立的,不要复用,只需加一个key属性:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

这样每次切换输入框都会被重新渲染。

v-show

不同是v-show元素始终会被渲染并保留在DOM中。

v-show只是简单切换元素的css属性display。

v-show不支持template也不支持v-else

对比v-show和v-if

  • v-if是真正的条件渲染,会确保切换过程中的销毁和重建。
  • v-if是惰性的:如果初始条件为假,则什么也不做,直到条件为真才开始渲染。
  • v-show不管什么条件都会渲染。
  • 所以,v-if有更高的切换开销,v-show有更高的渲染开销。

不推荐v-if和v-for一起使用

v-for比v-if有更高的优先级。

列表渲染

用v-for把数组对应为一组元素

<ul id="example-1">
  <li v-for="(item,index) in items">
    {{ item.message }}
  </li>
</ul>

v-for还支持可选的第二个参数,index,当前项的索引。

可以用of也可以用in

在v-for里使用对象

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

可以提供第二个参数为属性名称(也就是键名)

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

第三个参数为索引

在遍历对象时,会按照Object.keys()的结果遍历,但是不能保证它的结果在每个js引擎中都一样。

维护状态

为了给Vue提示,以便能跟踪每一个节点,从而重用和重新排序元素,需要给每一项提供一个key属性

<div v-for="item in items" v-bind:key="item.id">
  <!-- 内容 -->
</div>

key最好用字符串或者数值类型的值。

数组更新检测

变异方法(mutation method)

Vue将被侦听的数据的变异方法进行了包裹,所以它们也会触发视图更新,包括:

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

替换数组

非变异方法,例如filter(),concat(),slice()。它们不会改变原始数组,而是返回一个新数组,当使用非变异方法时,用新数组替换旧数组。

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

Vue为了使得DOM元素得到最大范围的重用,用一个含有相同元素的数组去替换页不会丢弃现有DOM重新渲染整个列表。

注意事项

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

  • 当利用索引直接设置数组项时:vm.items[indexOfItem] = newValue
  • 当修改数组长度时:vm.items.length = newLength

要直接设置并且可以出发响应式更新的话可以用:

Vue.set(vm.items,indexOfItem,newValue)
vm.items.splice(indexOfItem,1,newValue)

也可以使用vm.$set实例方法,是全局方法Vue.set的别名:

vm.$set(vm.items,indexOfItem,newValue)

改变长度可以用splice

对象变更检测注意事项

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

和上文类似使用set方法

Vue.set(vm.userProfile, 'age', 27)

或者

vm.$set(vm.userProfile, 'age', 27)

如果要给已有对象赋值多个新属性,应该用两个对象的属性创建新的对象:

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

显示过滤/排序后的结果

可以创建一个计算属性,返回过滤或排序后的数组

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

还可以使用方法:

<li v-for="n in even(numbers)">{{ n }}</li>
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>

在template上使用v-for

不推荐v-for和v-if一同使用

当他们处于同一节点,v-for优先级比v-if更高,意味着v-if将分别重复运行于每个v-for循环中。当只想渲染部分节点时,就很有用:

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

只渲染未完成的todo

如果是想条件地跳过循环,就把v-if置于外层:

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

在组件上使用v-for

要传数据必须使用prop

  <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>

这里的is="todo-item": 在ul中只有li会被看做有效内容。其实就是todo-item组件,但是可以避开一些潜在的浏览器解析错误。

事件处理

监听事件

使用v-on监听DOM事件,并在触发时运行一些js代码

事件处理方法

把这些代码写在methods里面

内联处理器中的方法

也可以在内联js语句中调用

<div id="example-3">
  <button v-on:click="say('hi')">Say hi</button>
  <button v-on:click="say('what')">Say what</button>
</div>

这种和直接写方法不一样,这种是写语句,直接写方法是传方法的名字过去。

有时候需要在内联语句中访问原始的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.preventDefault()或event.stopPropagation()是非常常见的需求。尽管可以在方法中实现,但更好的是用事件修饰符:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止单击事件继续传播 -->
<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>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

使用修饰符顺序很重要。v-on:click.prevent.self会阻止所有点击,而v-on:click.self.prevent只会阻止此元素自身的点击。

once修饰符还能用在自定义的组件事件。 还有.passive修饰符

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

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

不要把.passive和.prevent一起使用,因为.prevent将会被忽略。.passive会告诉浏览器你不想阻止事件的默认行为。

按键修饰符

在监听键盘事件时,需要知道详细的按键:

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

可以直接将KeyboardEvent.key暴露的任意有效按键名转换为连字符作为修饰符:

<input v-on:keyup.page-down="onPageDown">

按键码

有一些内置的别名:

  • .enter
  • .tab
  • .delete
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

还可以通过全局config.keyCodes对象自定义别名

Vue.config.keyCodes.f1 = 112

系统修饰符

实现在按下响应按键时触发鼠标或者键盘的监听:

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

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

必须按住才能触发

.exact修饰符

允许你控制由精准的系统修饰符组合触发的事件

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

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

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

鼠标按钮修饰符

  • .left
  • .right
  • .middle

为什么要在HTML监听事件

所有Vue事件处理方法和表达式都严格绑定在了当前视图的ViewModel上。

使用v-on的好处

  • 扫一眼html模板就能轻松定位js代码里对应的方法。
  • 无须在js中手动绑定事件
  • 当一个viewmodel被销毁,所有事件处理器都会自动删除。

表单输入绑定

基础用法

使用v-model在input、textarea、select上创建双向数据绑定。

其本质是语法糖。负责监听用户的输入事件以更新数据。

v-model会忽略所有表单元素的value、checked、selected属性的初始值,将Vue实例的数据作为数据来源。应通过js在组件的data中声明初始值。

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

  • text和textarea使用value属性和input事件
  • checkbox和radio使用checked和change事件
  • select将value作为prop并将change作为事件

中文日本等语言打拼音时用v-model不会更新,如要处理可以用input事件。

文本

多行文本

复选框

<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>

多个复选框放入一个数组:

<div id='example-3'>
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames">
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
  <label for="mike">Mike</label>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})

单选按钮

<div id="example-4">
  <input type="radio" id="one" value="One" v-model="picked">
  <label for="one">One</label>
  <br>
  <input type="radio" id="two" value="Two" v-model="picked">
  <label for="two">Two</label>
  <br>
  <span>Picked: {{ picked }}</span>
</div>
new Vue({
  el: '#example-4',
  data: {
    picked: ''
  }
})

选择框

<div id="example-5">
  <select v-model="selected">
    <option disabled value="">请选择</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})

如果v-model表达式的初始值没有匹配任何选项,select元素就会被渲染为未选中状态。在IOS中就不会触发change事件,建议像上面提供一个值为空的禁用选项。

多选时绑定到一个数组:

<div id="example-6">
  <select v-model="selected" multiple style="width: 50px;">
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '#example-6',
  data: {
    selected: []
  }
})

通常使用用v-for渲染选项。

值绑定

使用v-bind实现绑定value。

选择框的绑定

<select v-model="selected">
    <!-- 内联对象字面量 -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>
typeof vm.selected // => 'object'
vm.selected.number // => 123

修饰符

.lazy

在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步。可以添加lazy修饰符,从而转变为change事件进行同步:

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

.number

如果想自动将用户的输入值转为数值类型:

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

如果这个值无法被parserFloat()解析,就会返回原始值。

.trim

自动过滤用户输入的收尾空白字符:

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

在组件上使用v-model

比如一些富文本编辑器。

组件基础

基本示例

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

组件是可复用的Vue示例,且带有一个名字。我们可以在一个通过new Vue创建的Vue根示例中,通过自定义元素使用这个组件。

<div id="components-demo">
  <button-counter></button-counter>
</div>

组件的复用

data必须是一个函数

这样每个实例可维护一份被返回对象的独立拷贝:

data: function () {
  return {
    count: 0
  }
}

如果没有这条规则,点击一个按钮就会影响所有其他实例。

组件的组织

为了能使用必须注册以便Vue识别。

可以全局注册也可以局部注册。

全局注册:

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

全局注册的组件可以任何新创建的Vue实例中。

通过prop向子组件传递数据

可以在组件上注册一些自定义的attribute,当一个值传递给这个attribute时候,就变成了那个组件实例的一个属性。

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

可以使用v-bind动态传递prop。

单个根元素

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

监听子组件事件

Vue提供了一个自定义事件的系统解决监听子组件事件。父级组件可以通过v-on监听子组件实例的任意事件:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

同事子组件可以通过调用内建的$emit方法,并传入事件名称来触发一个事件:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

有了v-on绑定的监听器,父级组件就会接收到该事件并执行js。

使用事件抛出一个值

使用$emit的第二个参数来提供这个值:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

然后当父级组件监听到这个事件的时候,可以通过$event访问到被抛出的这个值。

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

如果这个事件处理函数的一个方法,那这个值就会作为第一个参数传入这个方法:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

在组件上使用v-model

自定义事件也用于创建支持v-model的自定义输入组件。

<input v-model="searchText">

等价于

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

当v-model用在组件上时,就会变成:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

而组件内的input必须:

  • 将value attribute绑定到一个名叫value的prop上
  • 在其input事件被触发时,将新的值通过自定义的input事件抛出
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

通过插槽分发内容

向组件传递内容

<alert-box>
  Something bad happened.
</alert-box>

在组件中加入slot

动态组件

在不同组件之间动态切换,通过给component元素加一个特殊的is attribute实现

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

通过is属性变成不同组件名来切换

解析DOM模板时的注意事项

对于ul,ol,table,select一些元素,对其内部是什么元素是有严格限制。 这会导致我们使用时出现问题:

<table>
  <blog-post-row></blog-post-row>
</table>

可以使用is attribute解决:

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