<div id="app"> {{ message }} </div> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
<div id="app-2"> <span v-bind:title="message"> 鼠标悬停几秒钟查看此处动态绑定的提示信息! </span> </div> var app2 = new Vue({ el: '#app-2', data: { message: '页面加载于 ' + new Date().toLocaleString() } })
<div id="app-3"> <p v-if="seen">如今你看到我了</p> </div> var app3 = new Vue({ el: '#app-3', data: { seen: true } })
<div id="app-4"> <ol> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div> var app4 = new Vue({ el: '#app-4', data: { todos: [ { text: '学习 JavaScript' }, { text: '学习 Vue' }, { text: '整个牛项目' } ] } })
<div id="app-5"> <p>{{ message }}</p> <button v-on:click="reverseMessage">逆转消息</button> </div> var app5 = new Vue({ el: '#app-5', data: { message: 'Hello Vue.js!' }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } })
Vue 还提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定。javascript
<div id="app-6"> <p>{{ message }}</p> <input v-model="message"> </div> var app6 = new Vue({ el: '#app-6', data: { message: 'Hello Vue!' } })
当一个 Vue 实例被建立时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的全部的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。html
// 咱们的数据对象 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 中存在的属性才是响应式的。vue
若是你知道你会在晚些时候须要一个属性,可是一开始它为空或不存在,那么你仅须要设置一些初始值。java
$data、$el、$watch
除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来ios
能够在 API 参考中查阅到完整的实例属性和方法的列表。web
好比 created 钩子能够用来在一个实例被建立以后执行代码:axios
new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 实例 console.log('a is: ' + this.a) } }) // => "a is: 1"
也有一些其它的钩子,在实例生命周期的不一样阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。api
beforeCreate、created、beforeMount、mounted、BeforeUpdate、updated、beforeDestroy、destroyed
注意:数组
不要在选项属性或回调上使用箭头函数,好比 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。由于箭头函数是和父级上下文绑定在一块儿的,this 不会是如你所预期的 Vue 实例,常常致使 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。浏览器
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 可以智能地计算出最少须要从新渲染多少组件,并把 DOM 操做次数减到最少。
若是你熟悉虚拟 DOM 而且偏心 JavaScript 的原始力量,你也能够不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。
经过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:
<span>Message: {{ msg }}</span> <span v-once>这个将不会改变: {{ msg }}</span>
<p>{{ rawHtml }}</p> <p><span v-html="rawHtml"></span></p>
注意,你不能使用 v-html 来复合局部模板,由于 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合做为可重用和可组合的基本单位。
注意:
你的站点上动态渲染的任意 HTML 可能会很是危险,由于它很容易致使 XSS 攻击。请只对可信内容使用 HTML 插值,毫不要对用户提供的内容使用插值。
Mustache 语法不能做用在 HTML 特性上,遇到这种状况应该使用 v-bind 指令
<div v-bind:id="dynamicId"></div> <button v-bind:disabled="isButtonDisabled">Button</button>
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>
指令 (Directives) 是带有 v- 前缀的特殊属性。指令属性的值预期是单个 JavaScript 表达式 (v-for 是例外状况,稍后咱们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地做用于 DOM。回顾咱们在介绍中看到的例子:
<p v-if="seen">如今你看到我了</p>
这里,v-if 指令将根据表达式 seen 的值的真假来插入/移除
元素。
一些指令可以接收一个“参数”,在指令名称以后以冒号表示。
<a v-bind:href="url">...</a> <a v-on:click="doSomething">...</a>
修饰符 (Modifiers) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
<form v-on:submit.prevent="onSubmit">...</form>
<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('') } } })
你能够像绑定普通属性同样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,所以当 vm.message 发生改变时,全部依赖 vm.reversedMessage 的绑定也会更新。
计算属性只有在它的相关依赖发生改变时才会从新求值。这就意味着只要 message 尚未发生改变,屡次访问 reversedMessage 计算属性会当即返回以前的计算结果,而没必要再次执行函数。
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 } } })
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 = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。
虽然计算属性在大多数状况下更合适,但有时也须要一个自定义的侦听器。这就是为何 Vue 经过 watch 选项提供了一个更通用的方法,来响应数据的变化。
当须要在数据变化时 执行异步 或开销较大的操做时,这个方式是最有用的。
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div> <script> 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.getAnswer() } }, methods: { // `_.debounce` 是一个经过 Lodash 限制操做频率的函数。 // 在这个例子中,咱们但愿限制访问 yesno.wtf/api 的频率 // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于 // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识, // 请参考:https://lodash.com/docs#debounce getAnswer: _.debounce( 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 }) }, // 这是咱们为断定用户中止输入等待的毫秒数 500 ) } }) </script>
除了 watch 选项以外,您还可使用命令式的 vm.$watch API。
直接绑对象
<div v-bind:class="{ active: isActive }"></div>
上面的语法表示 active 这个 class 存在与否将取决于数据属性 isActive
绑定多个class
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> data: { isActive: true, hasError: false }
绑定的数据对象没必要内联定义在模板里:
<div v-bind:class="classObject"></div> data: { classObject: { active: true, 'text-danger': false } }
返回对象的计算属性。这是一个经常使用且强大的模式:
<div v-bind:class="classObject"></div> 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' }
若是你也想根据条件切换列表中的 class,能够用三元表达式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
不过,当有多个条件 class 时这样写有些繁琐。因此在数组语法中也可使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
绑定内联
v-bind:style 的对象语法十分直观——看着很是像 CSS,但实际上是一个 JavaScript 对象。CSS 属性名能够用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 }
直接绑定到一个样式对象一般更好,这会让模板更清晰:
<div v-bind:style="styleObject"></div> data: { styleObject: { color: 'red', fontSize: '13px' } }
当 v-bind:style 使用须要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
多重值
<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>
添加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>
<h1 v-show="ok">Hello!</h1>
不一样的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
注意,v-show 不支持 元素,也不支持 v-else。
v-if 是“真正”的条件渲染,由于它会确保在切换过程当中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:若是在初始渲染时条件为假,则什么也不作——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——无论初始条件是什么,元素老是会被渲染,而且只是简单地基于 CSS 进行切换。
通常来讲,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。所以,若是须要很是频繁地切换,则使用 v-show 较好;若是在运行时条件不多改变,则使用 v-if 较好。
当 v-if 与 v-for 一块儿使用时,v-for 具备比 v-if 更高的优先级。
<ul id="example-1"> <li v-for="item in items"> //用of代替in也能够 {{ item.message }} </li> </ul> var example1 = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
v-for中第二个参数index
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> var example2 = new Vue({ el: '#example-2', data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
能够用v-for来遍历一个对象
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div> new Vue({ el: '#v-for-object', data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } })
建议尽量在使用 v-for 时提供 key,除非遍历输出的 DOM 内容很是简单,或者是刻意依赖默认行为以获取性能上的提高。
Vue 包含一组观察数组的变异方法,因此它们也将会触发视图更新。这些方法以下:
push() pop() shift() unshift() splice() sort() reverse()
例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但老是返回一个新数组。当使用非变异方法时,能够用新数组替换旧数组:
example1.items = example1.items.filter(function (item) { return item.message.match(/Foo/) })
注意:
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
vue都不能识别数组的变更
// Vue.set Vue.set(example1.items, indexOfItem, newValue) // Array.prototype.splice example1.items.splice(indexOfItem, 1, newValue) example1.items.splice(newLength)
能够用以上方法解决
有时,咱们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种状况下,能够建立返回过滤或排序数组的计算属性。
<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 }) } }
在计算属性不适用的状况下 (例如,在嵌套 v-for 循环中) 你可使用一个 method 方法:
<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 }) } }
<div id="example-2"> <!-- `greet` 是在下面定义的方法名 --> <button v-on:click="greet">Greet</button> </div> var example2 = new Vue({ el: '#example-2', data: { name: 'Vue.js' }, // 在 `methods` 对象中定义方法 methods: { greet: function (event) { // `this` 在方法里指向当前 Vue 实例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 if (event) { alert(event.target.tagName) } } } }) // 也能够用 JavaScript 直接调用方法 example2.greet() // => 'Hello Vue.js!'
能够用event做形参,能够传$event
事件修饰符
.stop .prevent .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>
使用修饰符时,顺序很重要;相应的代码会以一样的顺序产生。所以,用 @click.prevent.self 会阻止全部的点击,而 @click.self.prevent 只会阻止对元素自身的点击。
Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会当即触发 --> <!-- 而不会等待 `onScroll` 完成 --> <!-- 这其中包含 `event.preventDefault()` 的状况 --> <div v-on:scroll.passive="onScroll">...</div>
这个 .passive 修饰符尤为可以提高移动端的性能。
.enter .tab .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right <!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` --> <input v-on:keyup.13="submit">
.ctrl .alt .shift .meta <!-- 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
<input v-model="message" placeholder="edit me"> <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: [] } })
单选按钮
<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: '' } })
多选
<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: [] } })
在自定义组件中使用这些受限制的元素时会致使一些问题,例如:
<table> <my-row>...</my-row> </table>
自定义组件
<table> <tr is="my-row"></tr> </table>
应当注意,若是使用来自如下来源之一的字符串模板,则没有这些限制:
<script type="text/x-template"> JavaScript 内联模板字符串 .vue 组件
父传子,子经过props来接收
Vue.component('child', { // 声明 props props: ['message'], //经过驼峰xxSs // 就像 data 同样,prop 也能够在模板中使用 // 一样也能够在 vm 实例中经过 this.message 来使用 template: '<span>{{ message }}</span>' })
而后咱们能够这样向它传入一个普通字符串:
<child message="hello!"></child> //可使用xx-ss
若是你想把一个对象的全部属性做为 prop 进行传递,可使用不带任何参数的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。例如,已知一个 todo 对象:
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>
注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,若是 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
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
注意 prop 会在组件实例建立以前进行校验,因此在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还没法使用。
每一个 Vue 实例都实现了事件接口,即:
使用 $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 } } })
以下代码
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件须要更新 foo 的值时,它须要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
var bus = new Vue() // 触发组件 A 中的事件 bus.$emit('id-selected', 1) // 在组件 B 建立的钩子中监听事件 bus.$on('id-selected', function (id) { // ... })
另外一种定义模板的方式是在 JavaScript 标签里使用 text/x-template 类型,而且指定一个 id。例如:
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script> Vue.component('hello-world', { template: '#hello-world-template' })
这在有不少大模板的演示应用或者特别小的应用中可能有用,其它场合应该避免使用,由于这将模板和组件的其它定义分离了。