方法处理器
能够用 v-on 指令监听 DOM 事件:css
<div id="example"> <button v-on:click="greet">Greet</button> </div>
咱们绑定了一个单击事件处理器到一个方法 greet。下面在 Vue 实例中定义这个方法:vue
var vm = new Vue({ el: '#example', data: { name: 'Vue.js' }, // 在 `methods` 对象中定义方法 methods: { greet: function (event) { // 方法内 `this` 指向 vm alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 alert(event.target.tagName) } } }) // 也能够在 JavaScript 代码中调用方法 vm.greet() // -> 'Hello Vue.js!'
内联语句处理器json
除了直接绑定到一个方法,也能够用内联 JavaScript 语句:数组
<div id="example-2"> <button v-on:click="say('hi')">Say Hi</button> <button v-on:click="say('what')">Say What</button> </div> new Vue({ el: '#example-2', methods: { say: function (msg) { alert(msg) } } })
相似于内联表达式,事件处理器限制为一个语句。
有时也须要在内联语句处理器中访问原生 DOM 事件。能够用特殊变量 $event 把它传入方法:app
<button v-on:click="say('hello!', $event)">Submit</button> // ... methods: { say: function (msg, event) { // 如今咱们能够访问原生事件对象 event.preventDefault() } }
事件修饰符函数
在事件处理器中常常须要调用 event.preventDefault()
或 event.stopPropagation()
。尽管咱们在方法内能够轻松作到,不过让方法是纯粹的数据逻辑而不处理 DOM 事件细节会更好。布局
为了解决这个问题,Vue.js 为 v-on 提供两个 事件修饰符:.prevent 与 .stop。你是否还记得修饰符是点号打头的指令后缀?测试
<!-- 阻止单击事件冒泡 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件再也不重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符能够串联 --> <a v-on:click.stop.prevent="doThat"> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> 1.0.16 添加了两个额外的修饰符: <!-- 添加事件侦听器时使用 capture 模式 --> <div v-on:click.capture="doThis">...</div> <!-- 只当事件在该元素自己(而不是子元素)触发时触发回调 --> <div v-on:click.self="doThat">...</div>
按键修饰符动画
在监听键盘事件时,咱们常常须要检测 keyCode。Vue.js 容许为 v-on 添加按键修饰符:this
<!-- 只有在 keyCode 是 13 时调用 vm.submit() --> <input v-on:keyup.13="submit"> 记住全部的 keyCode 比较困难,Vue.js 为最经常使用的按键提供别名: <!-- 同上 --> <input v-on:keyup.enter="submit"> <!-- 缩写语法 --> <input @keyup.enter="submit">
所有的按键别名:
enter tab delete esc space up down left right
1.0.8+: 支持单字母按键别名。
1.0.17+: 能够自定义按键别名:
// 可使用 @keyup.f1 Vue.directive('on').keyCodes.f1 = 112
为何在 HTML 中监听事件?
你可能注意到这种事件监听的方式违背了传统理念 “separation of concern”。没必要担忧,由于全部的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会致使任何维护困难。实际上,使用 v-on 有几个好处:
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。 由于你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码能够是很是纯粹的逻辑,和 DOM 彻底解耦,更易于测试。 当一个 ViewModel 被销毁时,全部的事件处理器都会自动被删除。你无须担忧如何本身清理它们。
基础用法
能够用 v-model 指令在表单控件元素上建立双向数据绑定。根据控件类型它自动选取正确的方法更新元素。尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些极端例子。
(1)Text: <span>Message is: {{ message }}</span> <br> <input type="text" v-model="message" placeholder="edit me"> (2)Multiline text: <span>Multiline message is:</span> <p>{{ message }}</p> <br> <textarea v-model="message" placeholder="add multiple lines"></textarea> (3)Checkbox: 3-1.单个勾选框,逻辑值: <input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}</label> 3-2.多个勾选框,绑定到同一个数组: <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 | json }}</span> new Vue({ el: '...', data: { checkedNames: [] } }) (4)Radio: <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> (5)Select 5-1.单选: <select v-model="selected"> <option selected>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> 5-2.多选(绑定到一个数组): <select v-model="selected" multiple> <option selected>A</option> <option>B</option> <option>C</option> </select> <br> <span>Selected: {{ selected | json }}</span> 5-3.动态选项,用 v-for 渲染: <select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span> new Vue({ el: '...', data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } })
绑定 value
对于单选按钮,勾选框及选择框选项,v-model 绑定的 value 一般是静态字符串(对于勾选框是逻辑值):
<!-- 当选中时,`picked` 为字符串 "a" --> <input type="radio" v-model="picked" value="a"> <!-- `toggle` 为 true 或 false --> <input type="checkbox" v-model="toggle"> <!-- 当选中时,`selected` 为字符串 "abc" --> <select v-model="selected"> <option value="abc">ABC</option> </select>
可是有时咱们想绑定 value 到 Vue 实例的一个动态属性上,这时能够用 v-bind 实现,而且这个属性的值能够不是字符串。
1.Checkbox <input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b"> // 当选中时 vm.toggle === vm.a // 当没有选中时 vm.toggle === vm.b 2.Radio <input type="radio" v-model="pick" v-bind:value="a"> // 当选中时 vm.pick === vm.a 3.Select Options <select v-model="selected"> <!-- 对象字面量 --> <option v-bind:value="{ number: 123 }">123</option> </select> // 当选中时 typeof vm.selected // -> 'object' vm.selected.number // -> 123
参数特性
1.lazy
在默认状况下,v-model 在input 事件中同步输入框值与数据,能够添加一个特性 lazy,从而改到在 change 事件中同步:
<!-- 在 "change" 而不是 "input" 事件中更新 --> <input v-model="msg" lazy>
2.number
若是想自动将用户的输入转为 Number 类型(若是原值的转换结果为 NaN 则返回原值),能够添加一个特性 number:
<input v-model="age" number>
3.debounce
debounce 设置一个最小的延时,在每次敲击以后延时同步输入框的值与数据。若是每次更新都要进行高耗操做(例如在输入提示中 Ajax 请求),它较为有用。
<input v-model="msg" debounce="500">
注意 debounce 参数不会延迟 input 事件:它延迟“写入”底层数据。所以在使用 debounce 时应当用 vm.$watch() 响应数据的变化。若想延迟 DOM 事件,应当使用 debounce 过滤器。
经过 Vue.js 的过渡系统,能够在元素从 DOM 中插入或移除时自动应用过渡效果。Vue.js 会在适当的时机为你触发 CSS 过渡或动画,你也能够提供相应的 JavaScript 钩子函数在过渡过程当中执行自定义的 DOM 操做。
为了应用过渡效果,须要在目标元素上使用 transition 特性:
<div v-if="show" transition="my-transition"></div>
transition 特性能够与下面资源一块儿用:
v-if v-show v-for (只在插入和删除时触发,使用 vue-animated-list 插件) 动态组件 (介绍见组件) 在组件的根节点上,而且被 Vue 实例 DOM 方法(如 vm.$appendTo(el))触发。
当插入或删除带有过渡的元素时,Vue 将:
尝试以 ID "my-transition" 查找 JavaScript 过渡钩子对象——经过 Vue.transition(id, hooks) 或 transitions 选项注册。若是找到了,将在过渡的不一样阶段调用相应的钩子。 自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。 若是没有找到 JavaScript 钩子而且也没有检测到 CSS 过渡/动画,DOM 操做(插入/删除)在下一帧中当即执行。
CSS 过渡
示例:
典型的 CSS 过渡像这样:
<div v-if="show" transition="expand">hello</div>
而后为 .expand-transition, .expand-enter 和 .expand-leave 添加 CSS 规则:
/* 必需 */ .expand-transition { transition: all .3s ease; height: 30px; padding: 10px; background-color: #eee; overflow: hidden; } /* .expand-enter 定义进入的开始状态 */ /* .expand-leave 定义离开的结束状态 */ .expand-enter, .expand-leave { height: 0; padding: 0 10px; opacity: 0; }
你能够在同一元素上经过动态绑定实现不一样的过渡:
<div v-if="show" :transition="transitionName">hello</div> new Vue({ el: '...', data: { show: false, transitionName: 'fade' } })
另外,能够提供 JavaScript 钩子:
Vue.transition('expand', { beforeEnter: function (el) { el.textContent = 'beforeEnter' }, enter: function (el) { el.textContent = 'enter' }, afterEnter: function (el) { el.textContent = 'afterEnter' }, enterCancelled: function (el) { // handle cancellation }, beforeLeave: function (el) { el.textContent = 'beforeLeave' }, leave: function (el) { el.textContent = 'leave' }, afterLeave: function (el) { el.textContent = 'afterLeave' }, leaveCancelled: function (el) { // handle cancellation } })
过渡的 CSS 类名
类名的添加和切换取决于 transition 特性的值。好比 transition="fade",会有三个 CSS 类名:
.fade-transition 始终保留在元素上。 .fade-enter 定义进入过渡的开始状态。只应用一帧而后当即删除。 .fade-leave 定义离开过渡的结束状态。在离开过渡开始时生效,在它结束后删除。
若是 transition 特性没有值,类名默认是 .v-transition, .v-enter 和 .v-leave。
自定义过渡类名
1.0.14 新增
咱们能够在过渡的 JavaScript 定义中声明自定义的 CSS 过渡类名。这些自定义类名会覆盖默认的类名。当须要和第三方的 CSS 动画库,好比 Animate.css 配合时会很是有用:
<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div> Vue.transition('bounce', { enterClass: 'bounceInLeft', leaveClass: 'bounceOutRight' })
显式声明 CSS 过渡类型
1.0.14 新增
Vue.js 须要给过渡元素添加事件侦听器来侦听过渡什么时候结束。基于所使用的 CSS,该事件要么是 transitionend,要么是 animationend。若是你只使用了二者中的一种,那么 Vue.js 将可以根据生效的 CSS 规则自动推测出对应的事件类型。可是,有些状况下一个元素可能须要同时带有两种类型的动画。好比你可能但愿让 Vue 来触发一个 CSS animation,同时该元素在鼠标悬浮时又有 CSS transition 效果。这样的状况下,你须要显式地声明你但愿 Vue 处理的动画类型 (animation 或是 transition):
Vue.transition('bounce', { // 该过渡效果将只侦听 `animationend` 事件 type: 'animation' })
过渡流程详解
当 show 属性改变时,Vue.js 将相应地插入或删除 <div> 元素,按照以下规则改变过渡的 CSS 类名:
若是 show 变为 false,Vue.js 将: 调用 beforeLeave 钩子; 添加 v-leave 类名到元素上以触发过渡; 调用 leave 钩子; 等待过渡结束(监听 transitionend 事件); 从 DOM 中删除元素并删除 v-leave 类名; 调用 afterLeave 钩子。 若是 show 变为 true,Vue.js 将: 调用 beforeEnter 钩子; 添加 v-enter 类名到元素上; 把它插入 DOM; 调用 enter 钩子; 强制一次 CSS 布局,让 v-enter 确实生效。而后删除 v-enter 类名,以触发过渡,回到元素的原始状态; 等待过渡结束; 调用 afterEnter 钩子。
另外,若是在它的进入过渡还在进行中时删除元素,将调用 enterCancelled 钩子,以清理变更或 enter 建立的计时器。反过来对于离开过渡亦如是。
上面全部的钩子函数在调用时,它们的 this 均指向其所属的 Vue 实例。编译规则:过渡在哪一个上下文中编译,它的 this 就指向哪一个上下文。
最后,enter 和 leave 能够有第二个可选的回调参数,用于显式控制过渡如何结束。所以没必要等待 CSS transitionend 事件, Vue.js 将等待你手工调用这个回调,以结束过渡。例如:
enter: function (el) { // 没有第二个参数 // 由 CSS transitionend 事件决定过渡什么时候结束 } vs. enter: function (el, done) { // 有第二个参数 // 过渡只有在调用 `done` 时结束 }
当多个元素一块儿过渡时,Vue.js 会批量处理,只强制一次布局。
CSS 动画
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会当即删除,而是在 animationend 事件触发时删除。
示例: (省略了兼容性前缀)
<span v-show="show" transition="bounce">Look at me!</span> .bounce-transition { display: inline-block; /* 不然 scale 动画不起做用 */ } .bounce-enter { animation: bounce-in .5s; } .bounce-leave { animation: bounce-out .5s; } @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } @keyframes bounce-out { 0% { transform: scale(1); } 50% { transform: scale(1.5); } 100% { transform: scale(0); } }
JavaScript 过渡
也能够只使用 JavaScript 钩子,不用定义任何 CSS 规则。当只使用 JavaScript 过渡时,enter 和 leave 钩子须要调用 done 回调,不然它们将被同步调用,过渡将当即结束。
为 JavaScript 过渡显式声明 css: false 是个好主意,Vue.js 将跳过 CSS 检测。这样也会阻止无心间让 CSS 规则干扰过渡。
在下例中咱们使用 jQuery 注册一个自定义的 JavaScript 过渡:
Vue.transition('fade', { css: false, enter: function (el, done) { // 元素已被插入 DOM // 在动画结束后调用 done $(el) .css('opacity', 0) .animate({ opacity: 1 }, 1000, done) }, enterCancelled: function (el) { $(el).stop() }, leave: function (el, done) { // 与 enter 相同 $(el).animate({ opacity: 0 }, 1000, done) }, leaveCancelled: function (el) { $(el).stop() } })
而后用 transition 特性中:
<p transition="fade"></p>
渐近过渡
transition 与 v-for 一块儿用时能够建立渐近过渡。给过渡元素添加一个特性 stagger, enter-stagger 或 leave-stagger:
<div v-for="item in list" transition="stagger" stagger="100"></div>
或者,提供一个钩子 stagger, enter-stagger 或 leave-stagger,以更好的控制:
Vue.transition('stagger', { stagger: function (index) { // 每一个过渡项目增长 50ms 延时 // 可是最大延时限制为 300ms return Math.min(300, index * 50) } })