Vue笔记系列
一、Vue.js入门
二、Vue.js渐进
把一个普通 Javascript 对象传给 Vue 实例的 data选项,Vue 将遍历此对象全部的属性,并使用 Object.defineProperty(中文版) 把这些属性所有转为 getter/setter。
Object.defineProperty 是仅 ES5 支持,且没法 shim(什么是shim?) 的特性,这也就是为何 Vue 不支持 IE8 以及更低版本浏览器的缘由。javascript
Vue 不能检测到对象属性的添加或删除。因为 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,因此属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
解决方法就是以前提到的,可使用 Vue.set(object, key, value)
方法将响应属性添加到嵌套的对象上。还有就是以前提到的要注意,对象不能是 Vue 实例,或者 Vue 实例的根数据对象。css
因为 Vue 不容许动态添加根级响应式属性,干脆在一开始就就把该加的属性加上,因此你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值。html
参考Vue.js渐进中的API和实例方法中的关于nextTick的介绍。前端
Vue 在插入、更新或者移除 DOM 时,提供多种不一样方式的应用过渡效果。包括如下工具:vue
(1)单元素、组件的过渡java
Vue 提供了 transition 的封装组件,在下列情形中,能够给任何元素和组件添加 entering/leaving 过渡
条件渲染 (使用 v-if)
条件展现 (使用 v-show)
动态组件
组件根节点node
元素封装成过渡组件以后,在遇到插入或删除时,Vue 将
一、自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
二、若是过渡组件设置了过渡的 JavaScript 钩子函数,会在相应的阶段调用钩子函数。
三、若是没有找到 JavaScript 钩子而且也没有检测到 CSS 过渡/动画,DOM 操做(插入/删除)在下一帧中当即执行。git
过渡的-css-类名
会有 4 个(CSS)类名在 enter/leave 的过渡中切换v-enter
: 定义进入过渡的开始状态。在元素被插入时生效,在下一个帧移除。v-enter-active
: 定义进入过渡的结束状态。在元素被插入时生效,在 transition/animation 完成以后移除。v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时生效,在下一个帧移除。v-leave-active
: 定义离开过渡的结束状态。在离开过渡被触发时生效,在 transition/animation 完成以后移除。
图示:github
过渡的-css-类名 例子 ,注意里面星号部分
<!--css--> .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-active { opacity: 0 } <!--html--> <div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div> <!--js--> new Vue({ el: '#demo', data: { show: true } }) 若是<transition name="my-transition">中 name 没有设置,对于这些在 enter/leave 过渡中切换的类名,v- 是这些类名的默认前缀。 <!--css--> .v-enter-active, .v-leave-active { transition: opacity .5s } .v-enter, .v-leave-active { opacity: 0 } <!--html--> ... <transition> <p v-if="show">hello</p> </transition>
CSS 动画
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会当即删除,而是在 animationend 事件触发时删除。web
对于 Vue 的过渡系统和其余第三方 CSS 动画库,如过想跟 Animate.css 结合使用的话,Vue也准备了自定义过渡类名来控制,他们的优先级高于普通的类名。enter-class
enter-active-class
leave-class
leave-active-class
javaScript钩子
能够在属性中声明 JavaScript 钩子
<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) { // ... }, // 此回调函数是可选项的设置 // 与 CSS 结合时使用 enter: function (el, done) { // ... done() //当只用 JavaScript 过渡的时候, 在 enter 和 leave 中,回调函数 done 是必须的 。 不然,它们会被同步调用,过渡会当即完成。 }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave: function (el) { // ... }, // 此回调函数是可选项的设置 // 与 CSS 结合时使用 leave: function (el, done) { // ... done() //当只用 JavaScript 过渡的时候, 在 enter 和 leave 中,回调函数 done 是必须的 。 不然,它们会被同步调用,过渡会当即完成。 }, afterLeave: function (el) { // ... }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } }
JavaScript 钩子的例子,注意里面星号部分
<!-- html --> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <div id="example-4"> <button @click="show = !show"> Toggle </button> <transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" v-bind:css="false" ******推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也能够避免过渡过程当中 CSS 的影响。 > <p v-if="show"> Demo </p> </transition> </div>
//javascript new Vue({ el: '#example-4', data: { show: false }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.transformOrigin = 'left' }, enter: function (el, done) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }, { complete: done }) }, leave: function (el, done) { Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) Velocity(el, { rotateZ: '100deg' }, { loop: 2 }) Velocity(el, { rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0 }, { complete: done }) } } }) ******下面说一下,当只用 JavaScript 过渡的时候, 在 enter 和 leave 中,回调函数 done 是必须的 。 不然,它们会被同步调用,过渡会当即完成。 enter: function (el) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }) }, leave: function (el) { Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) Velocity(el, { rotateZ: '100deg' }, { loop: 2 }) Velocity(el, { rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0 }) ******能够看到done不仅是在Velocity的options中去掉了,并且参数中的done也去掉了。这是由于我尝试只去掉options中的done无论用,仍是正常动画,只有当参数中的done也去掉,元素离开的时候才是当即完成的,可是进入的过渡仍是存在。
(2)多个元素的过渡
对于原生标签可使用 v-if/v-else 。注意: 当有相同标签名的元素切换时,须要经过 key 特性设置惟一的值来标记以让 Vue 区分它们,不然 Vue 为了效率只会替换相同标签内部的内容。
例如:
<transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition>
(3)过渡模式
默认是进入和离开的过渡同时生效。
in-out: 新元素先进行过渡,完成以后当前元素过渡离开。
out-in: 当前元素先进行过渡,完成以后新元素过渡进入。
(4)多个组件的过渡
须要使用动态组件
多个组件过渡的例子
<!--CSS--> <style type="text/css"> #app div{ position: absolute; top: 40px; left: 0px; margin-left: 20px; } #app .component-fade-enter,#app .component-fade-leave-active { opacity: 0; } #app .component-fade-enter { left: -30px; } #app .component-fade-enter-active { transition: all .5s; } #app .component-fade-leave-active { left: 30px; transition: all .5s; } </style> <!--html--> <div id="app"> <button type="button" @click="change">改变</button> <transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> </div> <!--javascript--> <script> new Vue({ el: '#app', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } }, methods : { change : function (){ this.view == 'v-a'?this.view = 'v-b':this.view = 'v-a' } } }) </script>
(4)列表过渡
使用 <transition-group>
组件渲染列表。除了 mode,其余特性和 <transition> 相同。<transition-group>
与<transition>
的不一样点:
一、不一样于 <transition>
, `<transition-group>会以一个真实元素呈现:默认为一个 <span>。你也能够经过 tag 特性更换为其余元素。
二、内部元素 老是须要 提供惟一的 key 属性值
<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"> <!--元素是p,下面的key是数组的值--> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div>
列表的位移过渡
<transition-group> 支持经过 CSS transform 过渡移动。当一个子节点被更新,从屏幕上的位置发生变化,它将会获取应用 CSS 移动类(经过 name 属性或配置 move-class 属性自动生成)。
<div id="flip-list-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> </div> <!--没有move-class,像以前的类名同样,能够经过 name 属性来自定义前缀--> .flip-list-move { transition: transform 1s; } <transition-group name="flip-list" tag="ul" move-class="start"> ··· </transition-group> <!--经过 move-class 属性手动设置--> .start { transition: transform 1s; } 也能够这么写: <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item" class="start"> {{ item }} </li> </transition-group> <!--经过子元素的class 属性手动设置--> .start { transition: transform 1s; }
Vue 使用了一个叫 FLIP 简单的动画队列使用 transforms 将元素从以前的位置平滑过渡新的位置。
须要注意的是使用 FLIP 过渡的元素不能设置为 display: inline 。做为替代方案,能够设置为 display: inline-block 或者放置于 flex 中
Vue 的过渡系统提供了很是多简单的方法设置进入、离开和列表的动效(上面提到的那些)。对于数据元素自己的动效,好比:
数字和运算
颜色的显示
SVG 节点的位置
元素的大小和其余的属性**
全部的原始数字都被事先存储起来,能够直接转换到数字。能够结合 Vue 的响应式和组件系统,使用第三方库来实现切换元素的过渡状态。官方文档中使用的是Tween.js,tween.js是一款可生成平滑动画效果的js动画库,关于它的中文介绍可看一下这篇文章tween.js可生成平滑动画效果的js动画库。
这里面涉及到watch:
watch一个对象,键是须要观察的表达式,值是对应回调函数。值也能够是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每个属性。
var vm = new Vue({ data: { a: 1, b: 2, c: 3 }, watch: { a: function (val, oldVal) { console.log('new: %s, old: %s', val, oldVal) }, // 方法名 b: 'someMethod', // 深度 watcher c: { handler: function (val, oldVal) { /* ... */ }, deep: true } } }) vm.a = 2 // -> new: 2, old: 1
顺便再说一下实例方法vm.$watch( expOrFn, callback, [options] )
观察 Vue 实例变化的一个表达式或计算属性函数。回调函数获得的参数为新值和旧值。表达式只接受监督的键路径。对于更复杂的表达式,用一个函数取代。
注意:在变异(不是替换)对象或数组时,旧值将与新值相同,由于它们的引用指向同一个对象/数组。Vue 不会保留变异以前值的副本。(试了一下,没有进回调函数)
例子:
// 监督的键路径 vm.$watch('a.b.c', function (newVal, oldVal) { // 作点什么 }) // 更复杂的表达式==>函数 vm.$watch( function () { return this.a + this.b }, function (newVal, oldVal) { // 作点什么 } )
vm.$watch 返回一个取消观察函数,用来中止触发回调:
var unwatch = vm.$watch('a', cb) // 以后取消观察 unwatch()
选项:deep
为了发现对象内部值的变化,能够在选项参数中指定 deep: true 。注意监听数组的变更不须要这么作。
vm.$watch('someObject', callback, { deep: true }) vm.someObject.nestedValue = 123 // callback is fired???
选项:immediate
在选项参数中指定 immediate: true 将当即以表达式的当前值触发回调:
vm.$watch('a', callback, { immediate: true }) // 当即以 `a` 的当前值触发回调
Vue 推荐在绝大多数状况下使用 template 来建立你的 HTML。在某些状况须要用到比template 更接近编译器的render函数。
render 函数接收一个 createElement 方法做为第一个参数用来建立 VNode。
若是组件是一个函数组件,Render 函数还会接收一个额外的 context 参数,为没有实例的函数组件提供上下文信息。
createElement
接受的参数:
// @returns {VNode} createElement( // {String | Object | Function} // 一个 HTML 标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数,必要参数 'div', // {Object} // 一个包含模板相关属性的数据对象 // 这样,您能够在 template 中使用这些属性.可选参数. { }, // {String | Array} // 子节点(VNodes),能够是一个字符串或者一个数组. 可选参数. [ createElement('h1', 'hello world'), createElement(MyComponent, { props: { someProp: 'foo' } }), 'bar' ] )
createElement的第二个属性data Object参数详解
{ // 和`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 }, // 自定义指令. 注意事项:不能对绑定的旧值设值 // 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 => h('span', props.text) }, // 若是组件是其余组件的子组件,需为slot指定名称 slot: 'name-of-slot' // 其余特殊顶层属性 key: 'myKey', ref: 'myRef' }
函数化组件
标记组件为 functional, 组件无状态(没有 data),无实例(没有 this 上下文)。
Vue.component('my-component', { functional: true, // 为了弥补缺乏的实例 // 提供第二个参数做为上下文 render: function (createElement, context) { // ... }, // Props 可选 props: { // ... } })
组件须要的一切都是经过上下文传递,包括:
props: 提供props 的对象
children: VNode 子节点的数组
slots: slots 对象
data: 传递给组件的 data 对象
parent: 对父组件的引用
注意:slots() 和 children 对比
<my-functional-component> <p slot="foo"> first </p> <p>second</p> </my-functional-component>
对于这个组件,children 会给你两个段落标签,而 slots().default 只会传递第二个匿名段落标签,slots().foo 会传递第一个具名段落标签。同时拥有 children 和 slots() ,所以你能够选择让组件经过 slot() 系统分发或者简单的经过 children 接收,让其余组件去处理。
Vue.directive( id, [definition] )
注册或获取全局指令。
// 注册 Vue.directive('my-directive', { bind: function () {}, inserted: function () {}, update: function () {}, componentUpdated: function () {}, unbind: function () {} }) // 注册(传入一个简单的指令函数) Vue.directive('my-directive', function () { // 这里将会被 `bind` 和 `update` 调用 }) // getter,返回已注册的指令 var myDirective = Vue.directive('my-directive')
钩子函数
指令定义函数提供了几个钩子函数(可选):
钩子函数参数
钩子函数被赋予了如下参数:
binding: 一个对象,包含如下属性:
注意:除了 el以外,其它参数都应该是只读的,尽可能不要修改他们。若是须要在钩子之间共享数据,建议经过元素的 dataset 来进行。
例子:
html <div id="hook-arguments-example" v-demo:hello.a.b="message"></div> javascript Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } })
这个demo放到了github上,有时间会把它整理到个人github主页的一个小栏目里,那样就是方便看了。
从github上用各类方法下载到本地,找到index.html文件,双击就能看到效果
推荐一下微信公众号:《web前端教程》的一篇vue实战案例,你们能够关注一下这个公众号,他的教程都是挺新的,并且很基础很基础,个人这个demo就是在根据他的例子(特别是样式),增长了计数,增长了本地存储。
最后,这三篇文章是从个人简书里面搬来的。