共计 4531 个字符,预计需要花费 12 分钟才能阅读完成。
1. v-if 之 key
应用场景:在咱们登录的时候,用户能够应用用户账号以及用户电子邮箱进行登录,后盾接管账号及邮箱的参数都是同一个参数。
html 局部
<template v-if="loginType"> | |
<label>Username</label> | |
<input ref="input" placeholder="Enter your username"> | |
</template> | |
<template v-else> | |
<label>Email</label> | |
<input ref="input" placeholder="Enter your email address"> | |
</template> | |
<button @click="chage"> 切换 </button> | |
<div> | |
<button @click="submit"> 提交 </button> | |
</div> |
js 局部
chage(){ | |
let self = this; | |
self.loginType = !self.loginType; | |
}, | |
submit(){ | |
let self = this; | |
alert(self.$refs.input.value) | |
console.log(self.$refs.input.value); | |
} |
这样,简略的业务就实现了。可是这样就会呈现一些待优化的问题(当咱们切换输入框时,之前输出的内容还保留着)
产生这个问题的起因:Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
有时候这样也不总是符合实际需要,所以 Vue 为你提供了一种形式来表白“这两个元素是齐全独立的,不要复用它们”。只需增加一个具备惟一值的 key attribute 即可:
<template v-if="loginType"> | |
<label>Username</label> | |
<input ref="input" placeholder="Enter your username" key="username"> | |
</template> | |
<template v-else> | |
<label>Email</label> | |
<input ref="input" placeholder="Enter your email address" key="email"> | |
</template> | |
<button @click="chage"> 切换 </button> | |
<div> | |
<button @click="submit"> 提交 </button> | |
</div> |
2. 解析 DOM 模板之 is
有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素能够呈现在其外部是有严格限度的。而有些元素,诸如 <li>、<tr> 和 <option>,只能呈现在其它某些特定的元素外部。
这会导致咱们应用这些有约束条件的元素时遇到一些问题。例如:
<table> | |
<blog-post-row></blog-post-row> | |
</table> |
这个自定义组件 <blog-post-row> 会被作为有效的内容晋升到内部,并导致最终渲染后果出错。幸好这个非凡的 is attribute 给了咱们一个变通的方法:
<table> | |
<tr is="blog-post-row"></tr> | |
</table> |
须要留神的是如果咱们从以下起源应用模板的话,这条限度是不存在的:
- 字符串 (例如:template: ‘…’)
- 单文件组件 (.vue)
- <script type=”text/x-template”>
3. 组件之 v -model,.native 和 $listeners,.sync
* 在组件上应用 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)" | |
> | |
` | |
}) |
当初 v-model 就应该能够在这个组件上完满地工作起来了:
<custom-input v-model="searchText"></custom-input>
* 自定义组件的 v-model
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,然而像单选框、复选框等类型的输出控件可能会将 value attribute 用于不同的目标。model 选项能够用来防止这样的抵触:
Vue.component('base-checkbox', { | |
model: { | |
prop: 'checked', | |
event: 'change' | |
}, | |
props: {checked: Boolean}, | |
template: ` | |
<input | |
type="checkbox" | |
v-bind:checked="checked" | |
v-on:change="$emit('change', $event.target.checked)" | |
> | |
` | |
}) |
当初在这个组件上应用 v-model 的时候:
<base-checkbox v-model="lovingVue"></base-checkbox>
这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。
* 留神你依然须要在组件的 props 选项里申明 checked 这个 prop。
* 将原生事件绑定到组件
你可能有很屡次想要在一个组件的根元素上间接监听一个原生事件。这时,你能够应用 v-on 的 .native 修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
在有的时候这是很有用的,不过在你尝试监听一个相似 <input> 的十分特定的元素时,这并不是个好主见。比方上述 <base-input> 组件可能做了如下重构,所以根元素实际上是一个 <label> 元素:
<label> | |
{{label}} | |
<input | |
v-bind="$attrs" | |
v-bind:value="value" | |
v-on:input="$emit('input', $event.target.value)" | |
> | |
</label> |
这时,父级的 .native 监听器将静默失败。它不会产生任何报错,然而 onFocus 处理函数不会如你预期地被调用。
为了解决这个问题,Vue 提供了一个 $listeners property,它是一个对象,外面蕴含了作用在这个组件上的所有监听器。例如:
{focus: function (event) {/* ... */} | |
input: function (value) {/* ... */}, | |
} |
有了这个 $listeners property,你就能够配合 v-on=”$listeners” 将所有的事件监听器指向这个组件的某个特定的子元素。对于相似 <input> 的你心愿它也能够配合 v-model 工作的组件来说,为这些监听器创立一个相似下述 inputListeners 的计算属性通常是十分有用的:
Vue.component('base-input', { | |
inheritAttrs: false, | |
props: ['label', 'value'], | |
computed: {inputListeners: function () { | |
var vm = this | |
// `Object.assign` 将所有的对象合并为一个新对象 | |
return Object.assign({}, | |
// 咱们从父级增加所有的监听器 | |
this.$listeners, | |
// 而后咱们增加自定义监听器,// 或覆写一些监听器的行为 | |
{ | |
// 这里确保组件配合 `v-model` 的工作 | |
input: function (event) {vm.$emit('input', event.target.value) | |
} | |
} | |
) | |
} | |
}, | |
template: ` | |
<label> | |
{{label}} | |
<input | |
v-bind="$attrs" | |
v-bind:value="value" | |
v-on="inputListeners" | |
> | |
</label> | |
` | |
}) |
当初 <base-input> 组件是一个齐全通明的包裹器了,也就是说它能够齐全像一个一般的 <input> 元素一样应用了:所有跟它雷同的 attribute 和监听器都能够工作,不用再应用 .native 监听器。
* .sync 修饰符
在有些状况下,咱们可能须要对一个 prop 进行“双向绑定”。可怜的是,真正的双向绑定会带来保护上的问题,因为子组件能够变更父组件,且在父组件和子组件两侧都没有显著的变更起源。
这也是为什么咱们举荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个蕴含 title prop 的假如的组件中,咱们能够用以下办法表白对其赋新值的用意:
this.$emit('update:title', newTitle)
而后父组件能够监听那个事件并依据须要更新一个本地的数据 property。例如:
<text-document | |
v-bind:title="doc.title" | |
v-on:update:title="doc.title = $event" | |
></text-document> |
为了不便起见,咱们为这种模式提供一个缩写,即 .sync 修饰符:
<text-document v-bind:title.sync="doc.title"></text-document>
* 留神带有 .sync 修饰符的 v-bind 不能和表达式一起应用 (例如 v-bind:title.sync=”doc.title +‘!’”是有效的)。取而代之的是,你只能提供你想要绑定的 property 名,相似 v-model。
当咱们用一个对象同时设置多个 prop 的时候,也能够将这个 .sync 修饰符和 v-bind 配合应用:
<text-document v-bind.sync="doc"></text-document>
这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,而后各自增加用于更新的 v-on 监听器。
* 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{title: doc.title}”,是无奈失常工作的,因为在解析一个像这样的简单表达式的时候,有很多边缘状况须要思考。