<script>
引入(本地或者cdn)npm install vue
# 全局安装 vue-cli $ npm install --global vue-cli # 建立一个基于 webpack 模板的新项目 $ vue init webpack my-project # 安装依赖,走你 $ cd my-project $ npm install $ npm run dev
Vue (读音 /vjuː/,相似于 view) 是一套用于构建用户界面的渐进式框架。Vue 的核心库只关注视图层,对应view。css
Vue数据驱动,jQuery是结构驱动html
内部使用Object.defineProperty(最低支持IE9)把全部属性所有转为 getter/setter,为每一个组件绑定了watcher 实例对象,而且把属性做为依赖项,当依赖项的setter调用时,watcher将会从新计算,从而更新组件。vue
.png)node
<!--html--> <div id="app"> {{ message }} </div>
//js var vm = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
当一个 Vue 实例被建立时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的全部的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。react
// 咱们的数据对象 var data = { a: 1 } // 该对象被加入到一个 Vue 实例中 var vm = new Vue({ data: data }) // 他们引用相同的对象! vm.a === data.a // => true // 设置属性也会影响到原始数据 vm.a = 2 data.a // => 2 // ... 反之亦然 data.a = 3 vm.a // => 3
当这些数据改变时,视图会进行重渲染。值得注意的是只有当实例被建立时 data 中存在的属性是响应式的。也就是说若是你添加一个新的属性,将不会触发任何视图的更新。若是你知道你会在晚些时候须要一个属性,可是一开始它为空或不存在,那么你仅须要设置一些初始值。webpack
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` 改变后调用 })
vue实例自身暴露的属性和方法经过前缀$来获取git
var data = { a: 1 } var vm = new Vue({ el: '#example', data: data }) vm.$data === data // => true vm.$el === document.getElementById('example') // => true
每一个 Vue 实例在被建立以前都要通过一系列的初始化过程(生命周期)。在这个过程当中会运行一些叫作生命周期钩子的函数,用户能够在不一样阶段添加本身的代码来作一些事情。github
beforeCreate:
在实例初始化以后,数据观测 (data observer) 和 event/watcher 事件配置以前被调用。created:
在实例建立完成后被当即调用。在这一步,实例已完成如下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。beforeMount:
在挂载开始以前被调用:相关的 render 函数首次被调用。mounted:
el 被新建立的 vm.$el 替换,并挂载到实例上去以后调用该钩子。beforeUpdate:
数据更新时调用,发生在虚拟 DOM 从新渲染和打补丁以前。updated:
因为数据更改致使的虚拟 DOM 从新渲染和打补丁,在这以后会调用该钩子beforeDestroy:
实例销毁以前调用。在这一步,实例仍然彻底可用。destroyed:
Vue 实例销毁后调用。调用后,Vue 实例指示的全部东西都会解绑定,全部的事件监听器会被移除,全部的子实例也会被销毁。activated/deactivated:
keep-alive 组件激活/停用时调用,errorCaptured:
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子能够返回 false 以阻止该错误继续向上传播。注意:web
//错误,会致使this不会指向Vue 实例 created: () => console.log(this.a) vm.$watch('a', newValue => this.myMethod())
var vm = new Vue({ // 数据 data: "声明须要响应式绑定的数据对象", props: "接收来自父组件的数据", propsData: "建立实例时手动传递props,方便测试props", computed: "计算属性", methods: "定义能够经过vm对象访问的方法", watch: "Vue实例化时会调用$watch()方法遍历watch对象的每一个属性", // DOM el: "将页面上已存在的DOM元素做为Vue实例的挂载目标", template: "能够替换挂载元素的字符串模板", render: "渲染函数,字符串模板的替代方案", renderError: "仅用于开发环境,在render()出现错误时,提供另外的渲染输出", // 生命周期钩子 beforeCreate: "发生在Vue实例初始化以后,data observer和event/watcher事件被配置以前", created: "发生在Vue实例初始化以及data observer和event/watcher事件被配置以后", beforeMount: "挂载开始以前被调用,此时render()首次被调用", mounted: "el被新建的vm.$el替换,并挂载到实例上以后调用", beforeUpdate: "数据更新时调用,发生在虚拟DOM从新渲染和打补丁以前", updated: "数据更改致使虚拟DOM从新渲染和打补丁以后被调用", activated: "keep-alive组件激活时调用", deactivated: "keep-alive组件停用时调用", beforeDestroy: "实例销毁以前调用,Vue实例依然可用", destroyed: "Vue实例销毁后调用,事件监听和子实例所有被移除,释放系统资源", // 资源 directives: "包含Vue实例可用指令的哈希表", filters: "包含Vue实例可用过滤器的哈希表", components: "包含Vue实例可用组件的哈希表", // 组合 parent: "指定当前实例的父实例,子实例用this.$parent访问父实例,父实例经过$children数组访问子实例", mixins: "将属性混入Vue实例对象,并在Vue自身实例对象的属性被调用以前获得执行", extends: "用于声明继承另外一个组件,从而无需使用Vue.extend,便于扩展单文件组件", provide&inject: "2个属性须要一块儿使用,用来向全部子组件注入依赖,相似于React的Context", // 其它 name: "容许组件递归调用自身,便于调试时显示更加友好的警告信息", delimiters: "改变模板字符串的风格,默认为{{}}", functional: "让组件无状态(没有data)和无实例(没有this上下文)", model: "容许自定义组件使用v-model时定制prop和event", inheritAttrs: "默认状况下,父做用域的非props属性绑定会应用在子组件的根元素上。当编写嵌套有其它组件或元素的组件时,能够将该属性设置为false关闭这些默认行为", comments: "设为true时会保留而且渲染模板中的HTML注释" });
Vue.js 使用了基于 HTML 的模板语法,必须是合法的 HTML。在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。正则表达式
<!--Mustache--> <span>Message: {{ msg }}</span> <!--v-text--> <span v-text="msg"></span> <!--v-once:一次性插值--> <span v-once>这个将不会改变: {{ msg }}</span>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
只对可信内容使用 HTML 插值,毫不要对用户提供的内容使用插值。
<div v-bind:id="dynamicId"></div>
在插值中可使用表达式,但只限简单表达式。
{{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>
指令 (Directives) 是带有 v- 前缀的特殊属性。
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地做用于 DOM。
<p v-if="seen">如今你看到我了</p> <a v-on:click="doSomething">...</a>
指令 | 预期/限制 | 做用 |
---|---|---|
v-text | string | 文本插值 |
v-html | string | html插值 |
v-show | any | 条件显示 |
v-if、v-else、v-else-if | any | 条件渲染 |
v-for | Array/Object/number/string | 列表渲染 |
v-on(@) | Function/Inline Statement/Object | 事件绑定 |
v-bind(:) | any (with argument)/Object (without argument) | 特性绑定 |
v-model | 仅限<input>/<select>/<textarea>/components元素使用 | 双向绑定 |
v-pre | 忽略编译 | |
v-cloak | 避免显示Mustache | |
v-once | 一次性渲染 |
修饰符 (Modifiers) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
<form v-on:submit.prevent="onSubmit">...</form>
修饰符 | 做用 |
---|---|
.stop | 调用 event.stopPropagation()。 |
.prevent | 调用 event.preventDefault()。 |
.capture | 添加事件侦听器时使用 capture 模式。 |
.self | 只当事件是从侦听器绑定的元素自己触发时才触发回调。 |
.{keyCode / keyAlias} | 只当事件是从特定键触发时才触发回调。 |
.native | 监听组件根元素的原生事件。 |
.once | 只触发一次回调。 |
.left | (2.2.0) 只当点击鼠标左键时触发。 |
.right | (2.2.0) 只当点击鼠标右键时触发。 |
.middle | (2.2.0) 只当点击鼠标中键时触发。 |
.passive | (2.3.0) 以 { passive: true } 模式添加侦听器 |
修饰符 | 做用 |
---|---|
.prop | 被用于绑定 DOM 属性 (property)。(差异在哪里?) |
.camel | (2.1.0+) 将 kebab-case 特性名转换为 camelCase. (从 2.1.0 开始支持) |
.sync | (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。 |
修饰符 | 做用 |
---|---|
.lazy | 取代 input 监听 change 事件 |
.number | 输入字符串转为数字 |
.trim | 输入首尾空格过滤 |
对于任何复杂逻辑,你都应当使用计算属性,而不该直接放在模板中。
计算属性也是响应式的,可是它会基于它们的依赖进行缓存的,只有当缓存改变,它才会从新求值;不然会直接返回缓存的结果,而没必要再次执行函数。
应当优先使用计算属性而不是侦听属性。
<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('') } } })
下面的计算属性不会更新,由于Date.now() 不是响应式依赖。
computed: { now: function () { return Date.now() } }
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中 methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } }
方法在每次调用时总会再次执行函数。
计算属性默认只有 getter ,不过在须要时你也能够提供一个 setter
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] } } }
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div>
watch: { // 若是 `question` 发生改变,这个函数就会运行 question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.getAnswer() } }
// const unWatch = app.$watch('text', (newText, oldText) => { // console.log(`${newText} : ${oldText}`) // }) // setTimeout(() => { // unWatch() // }, 2000)
当value为真时,绑定对应的key到class
<!--内联在模板中--> <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> <!--绑定data或者计算属性的的一个对象--> <div v-bind:class="classObject"></div> <!--js--> data: { classObject: { active: true, 'text-danger': false } }
<!--模板--> <div v-bind:class="[activeClass, errorClass]"></div> <!--js--> data: { activeClass: 'active', errorClass: 'text-danger' } <!--结果--> <div class="active text-danger"></div>
也可使用三元表达式。
// isActive为真添加activeClass,errorClass始终存在 <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
class将被添加到该组件的根元素上面。该元素上已经存在的class不会被覆盖。
<my-component class="baz boo"></my-component>
注意:和普通的class并存,并不会覆盖(不一样名),最终会合成一个class。
自动侦测并添加相应浏览器引擎前缀。
CSS 属性名能够用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名。
<!--内联在模板中--> <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> <!--js--> data: { activeColor: 'red', fontSize: 30 } <!--绑定data或者计算属性的的一个对象--> <div v-bind:style="styleObject"></div> <!--js--> data: { styleObject: { color: 'red', fontSize: '13px' } }
能够将多个样式对象应用到同一个元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>
<!--经常使用于提供多个带前缀的值--> <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
根据表达式的值的真假条件渲染元素。
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>
若是须要条件渲染多个元素,可使用<template>包裹。
<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
Vue 会尽量高效地渲染元素,一般会复用已有元素而不是从头开始渲染。添加一个具备惟一值的 key 属性能够强制其从新渲染。
根据表达式之真假值,切换元素的 display CSS 属性。
<h1 v-show="ok">Hello!</h1>
<!--普通--> <ul id="example"> <li v-for="item in items"> {{ item.message }} </li> </ul> <!--带索引--> <ul id="example"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> <!--js--> var example = new Vue({ el: '#example', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
包含变异(改变原数组)和非变异(生成新数组,不改变原数组)两组方式,都将触发更新。
不能检测的变更:
<!--普通--> <li v-for="value in object"> {{ value }} </li> <!--带key--> <div v-for="(value, key) in object"> {{ key }}: {{ value }} </div> <!--带key、索引--> <div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div> <!--js--> new Vue({ data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } })
Vue 不能检测对象属性的添加或删除。
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 如今是响应式的 vm.b = 2 // `vm.b` 不是响应式的
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } }) vm.$set(this.userProfile, 'age', 27)
this.userProfile = Object.assign({}, this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
对应的删除属性使用vm.$delete(obj,key)
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。
建议尽量在使用 v-for 时为每一项提供一个惟一的 key。
循环组件的时候,key是必须的。
<div v-for="item in items" :key="item.id"> <!-- 内容 --> </div>
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
<div id="example-3"> <button v-on:click="say('hi')">Say hi</button> <!--访问原始的 DOM 事件--> <button v-on:click="say2('what', $event)">Say what</button> </div>
new Vue({ el: '#example-3', methods: { say: function (message) { alert(message) }, say2: function (message,event) { // 如今咱们能够访问原生事件对象 if (event) event.preventDefault() alert(message) } } })
修饰符能够串联,代码会以串联的顺序产生。
修饰符 | 做用 |
---|---|
.stop | 调用 event.stopPropagation()。 |
.prevent | 调用 event.preventDefault()。 |
.capture | 添加事件侦听器时使用 capture 模式。 |
.self | 只当事件是从侦听器绑定的元素自己触发时才触发回调。 |
.once | 只触发一次回调。 |
<!-- 阻止单击事件继续传播 --> <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>
Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符,可以提高移动端的性能,可是要避免和.prevent一块儿使用。
<!-- 滚动事件的默认行为 (即滚动行为) 将会当即触发 --> <!-- 而不会等待 `onScroll` 完成 --> <!-- 这其中包含 `event.preventDefault()` 的状况 --> <div v-on:scroll.passive="onScroll">...</div>
在监听键盘事件时,咱们常常须要检查常见的键值。Vue 容许为 v-on 在监听键盘事件时添加按键修饰符。
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` --> <input v-on:keyup.13="submit"> <!-- 缩写语法 --> <input @keyup.enter="submit">
.enter
、.tab
、.delete
(捕获“删除”和“退格”键)、.esc
、.space
、.up
、.down
、.left
、.right
// 可使用 `v-on:keyup.f1` Vue.config.keyCodes.f1 = 112
<!--可直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来做为修饰符:--> <input @keyup.page-down="onPageDown">
.ctrl
、.alt
、.shift
、.meta
。
在和 keyup 事件一块儿用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的状况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。
<!-- 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
仅响应特定的鼠标按钮
能够用 v-model
指令在表单 <input>
及 <textarea>
元素上建立双向数据绑定。
v-model
仅为v-on:input
和v-bind:value
的语法糖而已。
<input v-model="something"> <input v-bind:value="something" v-on:input="something = $event.target.value">
注意:v-model 会忽略全部表单元素的 value、checked、selected
特性的初始值而老是将 Vue 实例的数据做为数据来源。你应该经过 JavaScript 在组件的 data 选项中声明初始值。
<input v-model="message" placeholder="edit me"> <textarea v-model="message" placeholder="add multiple lines"></textarea> <p>Message is: {{ message }}</p>
<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: [] } }) //Checked names: [ "Jack", "John", "Mike" ]
<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: '' } }) //Picked: Two
<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: '' } }) //Selected: B
为多选时则返回一个数组Selected: [ "A", "B" ]
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" >
<input type="radio" v-model="pick" v-bind:value="a">
<select v-model="selected"> <!-- 内联对象字面量 --> <option v-bind:value="{ number: 123 }">123</option> </select>
.lazy
,默认input
事件触发,使用此修饰则改成change事件触发<!-- 在“change”时而非“input”时更新 --> <input v-model.lazy="msg" >
.number
将输入的值转换为数值.trim
过滤掉输入内容的首尾空白字符
组件 (Component) 是 Vue.js 最强大的功能之一。组件能够扩展 HTML 元素,封装可重用的代码。组件是具备特殊功能的自定义元素。
全部的 Vue 组件同时也都是 Vue 的实例,因此可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。
<div id="example"> <my-component></my-component> </div> //注意确保在初始化根实例以前注册组件 // 注册 Vue.component('my-component', { template: '<div>A custom component!</div>' })
var Child = { template: '<div>A custom component!</div>' } new Vue({ // ... components: { // <my-component> 将只在父组件模板中可用 'my-component': Child } })
webpack 的 vue cli3+
import Vue from 'vue' import upperFirst from 'lodash/upperFirst' import camelCase from 'lodash/camelCase' const requireComponent = require.context( // 其组件目录的相对路径 './components', // 是否查询其子目录 false, // 匹配基础组件文件名的正则表达式 /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(fileName => { // 获取组件配置 const componentConfig = requireComponent(fileName) // 获取组件的 PascalCase 命名 const componentName = upperFirst( camelCase( // 剥去文件名开头的 `'./` 和结尾的扩展名 fileName.replace(/^\.\/(.*)\.\w+$/, '$1') ) ) // 全局注册组件 Vue.component( componentName, // 若是这个组件选项是经过 `export default` 导出的, // 那么就会优先使用 `.default`, // 不然回退到使用模块的根。 componentConfig.default || componentConfig ) })
<ul>
、<ol>
、<table>
、<select>
这样的元素里面,为了遵循规范,应该使用is:<table> <tr is="my-row"></tr> </table>
如下类型模板无此限制:<script type="text/x-template">
、JavaScript 内联模板字符串、.vue
组件
能够包含<template>
、<script>
、<style>
、<docs>
四个元素。
<template>
内只容许有一个根元素<style>
能够有多个<docs>
说明文档<script>
、<style>
支持src导入父组件向子组件传递数据。
Vue.component('child', { // 声明 props props: ['message'], // 就像 data 同样,prop 也能够在模板中使用 // 一样也能够在 vm 实例中经过 this.message 来使用 template: '<span>{{ message }}</span>' }) <child message="hello!"></child>
<child v-bind:my-message="parentMsg"></child>
若是你想把一个对象的全部属性做为 prop 进行传递,可使用不带任何参数的 v-bind
todo: { text: 'Learn Vue', isComplete: false } <todo-item v-bind="todo"></todo-item> //等价于 <todo-item v-bind:text="todo.text" v-bind:is-complete="todo.isComplete" ></todo-item>
<!-- 传递了一个字符串 "1" --> <comp some-prop="1"></comp> <!-- 传递真正的数值 --> <comp v-bind:some-prop="1"></comp>
为组件的 prop 指定验证规则,会在组件实例建立以前进行校验。若是传入的数据不符合要求,Vue 会发出警告。
Vue.component('example', { props: { // 基础类型检测 (`null` 指容许任何类型) propA: Number, // 多是多种类型 propB: [String, Number], // 必传且是字符串 propC: { type: String, required: true }, // 数值且有默认值 propD: { type: Number, default: 100 }, // 数组/对象的默认值应当由一个工厂函数返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { return value > 10 } } } })
type 能够是下面原生构造器:String
、Number
、Boolean
、Function
、Object
、Array
、Symbol
组件能够接收任意传入的特性,这些特性都会被添加到组件的根元素上,且会作合并处理。
子组件向父组件传递数据。
$on(eventName)
监听事件$emit(eventName)
触发事件<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div>
Vue.component('button-counter', { template: '<button v-on:click="incrementCounter">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementCounter: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })
.sync
@update
的语法糖
<comp :foo.sync="bar"></comp> this.$emit('update:foo', newValue)
等价于
<comp :foo="bar" @update:foo="val => bar = val"></comp> this.$emit('update:foo', newValue)
v-on:input
和v-bind:value
的语法糖
<input v-model="something"> // 经过 input 事件带出数值 this.$emit('input', Number(formattedValue))
等价于
<input v-bind:value="something" v-on:input="something = $event.target.value"> this.$emit('input', Number(formattedValue))
bus.js
var bus = new Vue() // 触发组件 A 中的事件 bus.$emit('id-selected', 1) // 在组件 B 建立的钩子中监听事件 bus.$on('id-selected', function (id) { // ... })
注: 还可使用$ref、$parent、$child
进行通讯,不过不推荐。
为了让组件能够组合,咱们须要一种方式来混合父组件的内容与子组件本身的模板。这个过程被称为内容分发。
编译做用域: 父组件模板的内容在父组件做用域内编译;子组件模板的内容在子组件做用域内编译。
除非子组件模板包含至少一个 <slot>
插口,不然父组件的内容将会被丢弃。当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片断将插入到插槽所在的 DOM 位置,并替换掉插槽标签自己。
最初在 <slot>
标签中的任何内容都被视为备用内容。备用内容在子组件的做用域内编译,而且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
<!--子组件--> <div> <h2>我是子组件的标题</h2> <slot> 只有在没有要分发的内容时才会显示。 </slot> </div> <!--父组件--> <div> <h1>我是父组件的标题</h1> <my-component> <p>这是一些初始内容</p> <p>这是更多的初始内容</p> </my-component> </div> <!--结果--> <div> <h1>我是父组件的标题</h1> <div> <h2>我是子组件的标题</h2> <p>这是一些初始内容</p> <p>这是更多的初始内容</p> </div> </div>
<slot>
元素能够用一个特殊的特性 name 来进一步配置如何分发内容。多个插槽能够有不一样的名字。具名插槽将匹配内容片断中有对应 slot 特性的元素。
仍然能够有一个匿名插槽,它是默认插槽,做为找不到匹配的内容片断的备用插槽。若是没有默认插槽,这些找不到匹配的内容片断将被抛弃。
<!--子组件--> <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> <!--父组件--> <app-layout> <h1 slot="header">这里多是一个页面标题</h1> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> <p slot="footer">这里有一些联系信息</p> </app-layout> <!--结果--> <div class="container"> <header> <h1>这里多是一个页面标题</h1> </header> <main> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> </main> <footer> <p>这里有一些联系信息</p> </footer> </div>
和普通的插槽对比,可以传递数据。
<!--子组件--> <div class="child"> <slot text="hello from child"></slot> </div> <!--父组件--> <div class="parent"> <child> <!--2.5.0+,slot-scope 能被用在任意元素或组件中而再也不局限于 <template>--> <template slot-scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div> <!--结果--> <div class="parent"> <div class="child"> <span>hello from parent</span> <span>hello from child</span> </div> </div>
经过使用保留的 <component>
元素,并对其 is 特性进行动态绑定,你能够在同一个挂载点动态切换多个组件:
var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
把切换出去的组件保留在内存中,保留其状态或避免从新渲染
<keep-alive> <component :is="currentView"> <!-- 非活动组件将被缓存! --> </component> </keep-alive>
Vue 在插入、更新或者移除 DOM 时,提供多种不一样方式的应用过渡效果。
适用场景:条件渲染 (使用 v-if)、条件展现 (使用 v-show)、动态组件、组件根节点
<div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div>
new Vue({ el: '#demo', data: { show: true } })
.fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; }
动画在css中使用animation便可,其余和过渡相似。
咱们能够经过如下特性来自定义过渡类名:enter-class、enter-active-class、enter-to-class (2.1.8+)、leave-class、leave-active-class、leave-to-class (2.1.8+)
<div id="example-3"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div>
<transition :duration="1000">...</transition> <transition :duration="{ enter: 500, leave: 800 }">...</transition>
<transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition>
// ... methods: { // -------- // 进入中 // -------- beforeEnter: function (el) { // ... }, // 此回调函数是可选项的设置,done 是必须的 // 与 CSS 结合时使用 enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave: function (el) { // ... }, // 此回调函数是可选项的设置,done 是必须的 // 与 CSS 结合时使用 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } }
能够经过 appear 特性设置节点在初始渲染的过渡
<!--css--> <transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition> <!--JS钩子--> <transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" > <!-- ... --> </transition>
当有相同标签名的元素切换时,建议给元素设置key。
<transition name="fade" mode="out-in"> <!-- ... the buttons ... --> </transition>
多个组件的过渡使用动态组件
<!--html--> <transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> <!--js--> new Vue({ el: '#transition-components-demo', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } })
使用 <transition-group>
组件。
<span>
。你也能够经过 tag 特性更换为其余元素。<div id="list-demo" class="demo"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div>
<transition-group>
组件还有一个特殊之处。不只能够进入和离开动画,还能够改变定位。v-move 特性,它会在元素的改变定位的过程当中应用。
<!--html--> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> <!--css--> .flip-list-move { transition: transform 1s; }
也能够经过 move-class 属性手动设置
<transition name="very-special-transition" mode="out-in" v-on:before-enter="beforeEnter" v-on:after-enter="afterEnter"> <slot></slot> </transition>
<transition v-bind:name="transitionName"> <!-- ... --> </transition>
混合 (mixins) 是一种分发 Vue 组件中可复用功能的很是灵活的方式。混合对象能够包含任意组件选项。当组件使用混合对象时,全部混合对象的选项将被混入该组件自己的选项。
// 定义一个混合对象 var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } } // 定义一个使用混合对象的组件 var Component = Vue.extend({ mixins: [myMixin] })
Vue.extend()
也使用一样的策略进行合并。除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也容许注册自定义指令。
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } }) // 注册一个局部自定义指令 directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } } //使用 <input v-focus>
一个指令定义对象能够提供以下几个钩子函数 (均为可选):
bind:
只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。inserted:
被绑定元素插入父节点时调用 (仅保证父节点存在,但不必定已被插入文档中)。update:
所在组件的 VNode 更新时调用,可是可能发生在其子 VNode 更新以前。指令的值可能发生了改变,也可能没有。可是你能够经过比较更新先后的值来忽略没必要要的模板更新 (详细的钩子函数参数见下)。componentUpdated:
指令所在组件的 VNode 及其子 VNode 所有更新后调用。unbind:
只调用一次,指令与元素解绑时调用。指令钩子函数会被传入如下参数:
el:
指令所绑定的元素,能够用来直接操做 DOM 。binding:
一个对象,包含如下属性:
name:
指令名,不包括 v- 前缀。value:
指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。oldValue:
指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。不管值是否改变均可用。expression:
字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。arg:
传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。modifiers:
一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。vnode:
Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode:
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。https://cn.vuejs.org/v2/guide...
createElement
// @returns {VNode} createElement( // {String | Object | Function} // 一个 HTML 标签字符串,组件选项对象,或者 // 解析上述任何一种的一个 async 异步函数,必要参数。 'div', // {Object} // 一个包含模板相关属性的数据对象 // 这样,您能够在 template 中使用这些属性。可选参数。 { // (详情见下面的数据对象) }, // {String | Array} // 子节点 (VNodes),由 `createElement()` 构建而成, // 或使用字符串来生成“文本节点”。可选参数。 [ '先写一些文字', createElement('h1', '一则头条'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
数据对象:
{ // 和`v-bind:class`同样的 API 'class': { foo: true, bar: false }, // 和`v-bind:style`同样的 API style: { color: 'red', fontSize: '14px' }, // 正常的 HTML 特性 attrs: { id: 'foo' }, // 组件 props props: { myProp: 'bar' }, // DOM 属性 domProps: { innerHTML: 'baz' }, // 事件监听器基于 `on` // 因此再也不支持如 `v-on:keyup.enter` 修饰器 // 须要手动匹配 keyCode。 on: { click: this.clickHandler }, // 仅对于组件,用于监听原生事件,而不是组件内部使用 // `vm.$emit` 触发的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定义指令。注意,你没法对 `binding` 中的 `oldValue` // 赋值,由于 Vue 已经自动为你进行了同步。 directives: [ { name: 'my-custom-directive', value: '2', expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], // Scoped slots in the form of // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 若是组件是其余组件的子组件,需为插槽指定名称 slot: 'name-of-slot', // 其余特殊顶层属性 key: 'myKey', ref: 'myRef' }
过滤器能够用在两个地方:双花括号插值和 v-bind 表达式。
<!-- 在双花括号中 --> {{ message | capitalize }} <!-- 在 `v-bind` 中 --> <div v-bind:id="rawId | formatId"></div>
//定义局部过滤器 filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } //定义全局过滤器 Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) })
{{ message | filterA | filterB }}
{{ message | filterA('arg1', arg2) }}
<script>
引入(本地或者cdn)npm install vue
必需要经过 Vue.use()
明确地安装路由功能,且要经过 router 配置参数注入Vue实例,从而让整个应用都有路由功能。
将页面组件(components)映射到路由(routes),而后告诉 vue-router 在哪里渲染它们
to:
属性指定目标地址,默认渲染成带有正确连接的 标签, replace:
至关于router.replace()
不会留下 history 记录append:
设置 append 属性后,则在当前(相对)路径前添加基路径。例如,咱们从 /a 导航到一个相对路径 b,若是没有配置 append,则路径为 /b,若是配了,则为 /a/btag:
属性生成别的标签.。另外,当目标路由成功激活时,连接元素自动设置一个表示激活的 CSS 类名。active-class:
连接激活时使用的 CSS 类名。默认值能够经过路由的构造选项 linkActiveClass 来全局配置。将激活 class 应用在外层元素:
<router-link tag="li" to="/foo"> <a>/foo</a> </router-link>
在这种状况下,<a>
将做为真实的连接(它会得到正确的 href 的),而 "激活时的CSS类名" 则设置到外层的 <li>
。
路由视图容器
<transition> <!--使用路由缓存--> <keep-alive> <router-view></router-view> </keep-alive> </transition>
若是 <router-view>
设置了名称,则会渲染对应的路由配置中 components 下的相应组件。
<!--html--> <router-view class="view one"></router-view> <router-view class="view two" name="a"></router-view> <router-view class="view three" name="b"></router-view> <!--js--> const router = new VueRouter({ routes: [ { path: '/', components: { default: Foo, a: Bar, b: Baz } } ] })
params
//定义 routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] //调用 $route.params.id
query
//定义 routes: [ // 动态路径参数 以冒号开头 { path: '/user?id=6456456', component: User } ] //调用 $route.query.id
当路由参数变化时,组件的生命周期钩子不会再被调用。
想对路由参数的变化做出响应的话,有如下两种方式:
const User = { template: '...', watch: { '$route' (to, from) { // 对路由变化做出响应... } } }
const User = { template: '...', beforeRouteUpdate (to, from, next) { // react to route changes... // don't forget to call next() } }
同一个路径能够匹配多个路由时,谁先定义的,谁的优先级就最高。
所以,404类的页面必定要放在最后,路由是按照声明顺序匹配,若是不是最后则404以后的页面都会跳转到404。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
导航到不一样的 URL,会向 history 栈添加一个新的记录。
在 Vue 实例内部,调用 this.$router.push
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
和router.push功能同样,惟一区别就是不会向 history 添加新记录
前进或后退nN步,相似 window.history.go(n)
// 在浏览器记录中前进一步,等同于 history.forward() router.go(1) // 后退一步记录,等同于 history.back() router.go(-1)
const router = new VueRouter({ routes: [ //path { path: '/a', redirect: '/b' }, //name { path: '/a', redirect: { name: 'foo' }}, //方法 { path: '/a', redirect: to => { // 方法接收 目标路由 做为参数 // return 重定向的 字符串路径/路径对象 }} ] })
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,可是路由匹配则为 /a,就像用户访问 /a 同样
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
使用 props 将组件和路由解耦
const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // 对于包含命名视图的路由,你必须分别为每一个命名视图添加 `props` 选项: { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ] })
const router = new VueRouter({ routes: [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } ] })
const router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } ] })
vue-router 默认 hash 模式。
开启history 模式,将充分利用 history.pushState API 来完成 URL 跳转而无须从新加载页面,但须要后端配合。
const router = new VueRouter({ mode: 'history', routes: [...] })
vue-router 提供的导航守卫主要用来经过跳转或取消的方式守卫导航。
//前置守卫:确保要调用 next 方法,不然钩子就不会被 resolved。 router.beforeEach((to, from, next) => { // ... }) //后置守卫 router.afterEach((to, from) => { // ... }) //解析守卫:在导航被确认以前,同时在全部组件内守卫和异步路由组件被解析以后,解析守卫就被调用 router.beforeResolve((to, from) => { // ... })
to: Route:
即将要进入的目标 路由对象from: Route:
当前导航正要离开的路由next: Function:
必定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
next():
进行管道中的下一个钩子。若是所有钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false):
中断当前的导航。若是浏览器的 URL 改变了(多是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。next('/')
或者 next({ path: '/' }):
跳转到一个不一样的地址。当前的导航被中断,而后进行一个新的导航。你能够向 next 传递任意位置对象,且容许设置诸如 replace: true、name: 'home'
之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。next(error):
(2.4.0+) 若是传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError()
注册过的回调。//与全局前置守卫的方法参数是同样的 const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 由于当守卫执行前,组件实例还没被建立 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,可是该组件被复用时调用 // 举例来讲,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 因为会渲染一样的 Foo 组件,所以组件实例会被复用。而这个钩子就会在这个状况下被调用。 // 能够访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 能够访问组件实例 `this` } }
beforeRouteEnter 守卫 不能 访问 this,由于守卫在导航确认前被调用,所以即将登场的新组件还没被建立。能够经过传一个回调给 next来访问组件实例。
beforeRouteEnter (to, from, next) { next(vm => { // 经过 `vm` 访问组件实例 }) }
配置meta字段记录元信息
//定义 { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } //访问 $route.matched
<transition> <router-view></router-view> </transition> <!-- 使用动态的 transition name --> <transition :name="transitionName"> <router-view></router-view> </transition>
<script>
引入(本地或者cdn)npm install vuex
必需要经过 Vue.use() 明确地安装vuex,且要经过 store 配置参数注入Vue实例。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以使代码更简练 count: state => state.count, // 传字符串参数 'count' 等同于 `state => state.count` countAlias: 'count', // 为了可以使用 `this` 获取局部状态,必须使用常规函数 countPlusLocalState (state) { return state.count + this.localCount } }) } -------------- //当映射的计算属性的名称与 state 的子节点名称相同时,咱们也能够给 mapState 传一个字符串数组 computed: mapState([ // 映射 this.count 为 store.state.count 'count' ]) -------------- computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
若是有多处都须要从store中派生(进行二次处理)出一些状态,那么可使用getter(store 的计算属性,依赖更新)
getters: { //state 做为其第一个参数 doneTodos: state => { return state.todos.filter(todo => todo.done) }, //接受其余 getter 做为第二个参数 doneTodosCount: (state, getters) => { return getters.doneTodos.length } } //调用 store.getters.doneTodosCount // -> 1
import { mapGetters } from 'vuex' computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) }
更改 Vuex 的 store 中的状态的惟一方法是提交 (commit)。建议名字大写。 mutation,可是请勿进行异步操做。
mutations: { increment (state) { // 变动状态 state.count++ } } //调用 store.commit('increment')
载荷即commit中额外的参数。
mutations: { increment (state, n) { state.count += n } } //调用 store.commit('increment', 10) ------------- //推荐使用对象 mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 }) //对象风格提交 store.commit({ type: 'increment', amount: 10 })
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` // `mapMutations` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')` }) } }
Action 相似于 mutation,区别在于:
actions: { increment (context) { context.commit('increment') } } //分发 store.dispatch('increment')
Action 函数接受一个与 store 实例(不是 store 实例自己)具备相同方法和属性的 context(context.state/context.getters/context.commit
)对象,也能够运用参数结构。
actions: { increment ({ commit }) { commit('increment') } }
// 以载荷形式分发 store.dispatch('incrementAsync', { amount: 10 }) // 以对象形式分发 store.dispatch({ type: 'incrementAsync', amount: 10 })
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` // `mapActions` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` }) } }
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) }, //调用其余action actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } } store.dispatch('actionA').then(() => { // ... })
// 假设 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } }
将store分割成模块,每一个模块拥有本身的 state、mutation、action、getter。
actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } }
modules: { account: { namespaced: true, // 模块内容(module assets) state: {}, // 模块内的状态已是嵌套的了,使用 `namespaced` 属性不会对其产生影响 getters: {}, actions: {}, mutations: {} } }
getters: { // 在这个模块的 getter 中,`getters` 被局部化了 // 你可使用 getter 的第四个参数来调用 `rootGetters` someGetter (state, getters, rootState, rootGetters) {} } actions: { // 在这个模块中, dispatch 和 commit 也被局部化了 // 他们能够接受 `root` 属性以访问根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) {} }
computed: { ...mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions('some/nested/module', [ 'foo', 'bar' ]) }
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') export default { computed: { // 在 `some/nested/module` 中查找 ...mapState({ a: state => state.a, b: state => state.b }) }, methods: { // 在 `some/nested/module` 中查找 ...mapActions([ 'foo', 'bar' ]) } }
store.registerModule
// 注册模块 `myModule` store.registerModule('myModule', { // ... }) // 注册嵌套模块 `nested/myModule` store.registerModule(['nested', 'myModule'], { // ... })
使用store.unregisterModule(moduleName)
来动态卸载模块
在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的状况下,你仍然须要对普通 DOM 元素进行底层操做,这时候就会用到自定义指令
建立Vue的自定义指令的这五个钩子函数都是可选的,不必定要所有出现。而这其中bind和update两个钩子函数是最有用的。在实际使用的时候,咱们应该根据需求作不一样的选择。好比在恰当的时间经过bind钩子函数去初始化实例,update钩子函数去作对应的参数更新和使用unbind钩子函数去释放实例资源占用等。
bind(el, binding, vnode) inserted(el, binding, vnode) update(el, binding, vnode, oldVnode) componentUpdated(el, binding, vnode, oldVnode) unbind(el, binding, vnode)
指令钩子函数会被传入如下参数:
el:指令所绑定的元素,能够用来直接操做DOM binding:一个对象,这个对象包含一些属性,稍后列出每一个属性的含义 vnode:Vue编译生成的虚拟节点。有关于VNode更多的资料,能够阅读VNode相关的API oldVnode:上一个虚拟节点,仅在update和componentUpdated两个钩子函数中可用
binding参数是一个对象,其包含如下一些属性:
name:指令名,不包括v-前缀 value:指令的绑定值,如例v-hello = "1 + 1"中,绑定值为2 oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,不管值是否改变均可用 expression:字符串形式的指令表达式。例如v-hello = "1 + 1"中,表达式为"1 + 1" arg:传给指令的参数,可选。例如v-hello:message中,参数为"message" modifiers:一个包含修饰符的对象。例如v-hello.foo.bar中,修饰符对象为{foo:true, bar:true}
除了 el 以外,其它参数都应该是只读的,切勿进行修改。若是须要在钩子之间共享数据,建议经过元素的 dataset 来进行。著做权归做者全部。
在不少时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。好比这样写:
Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value })
若是指令须要多个值,能够传入一个 JavaScript 对象字面量。记住,指令函数可以接受全部合法的 JavaScript 表达式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" })
参考资料:
https://pablohpsilva.github.i...
https://vue-loader.vuejs.org/...