种子的希望

时间:2018-06-30 05:57:56来源:杰瑞文章网点击:作文字数:700字
深入响应式 追踪变化: 把普通js对象传给Vue实例的data选项,Vue将使用Object.defineProperty把属性转化为getter/setter(因此不支持IE8及以下),每个组件实例都有相应的watcher实例对象,它把属性记录为依赖,当依赖项的setter被调用的时候,watcher会被通知并重新计算,从而更新渲染 变化检测: Vue不能检测到对象属性的添加或删除,因此属性必须在data对象上存在才能让Vue转换它,才是响应式的 Vue不允许在已经创建的实例上动态添加新的根级响应式属性,但是可以将响应属性添加到嵌套的对象上,使用Vue.set(object,key,value) Vue.set(vm.someObject,'b',2) 还可以用vm.$set实例方法,是Vue.set的别名: this.$set(this.someObject,'b',2) 想向已有对象添加一些属性,可以创建一个新的对象,让它包含原对象的属性和新属性: this.someObject=Object.assign({},this.someObject,{a:1,b:2}) 声明响应式属性:由于不允许动态添加根级响应式属性,所以初始化实例前要声明,即便是个空值: var vm = new Vue({ data: { // 声明 message 为一个空值字符串 message: '' }, template: '
{{ message }}
' }) // 之后设置 `message` vm.message = 'Hello!' Vue是异步更新队列的,目的是缓冲同一个事件循环中所有数据变化去除重复数据,但是问题来了,当设置数据变化时,并不会立即重新渲染,需要排队,可是如果想要在这个变化后紧接着做点什么,就需要一个Vue.nextTick(callback)来表明,这个更新后再执行操作:
{{message}}
var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true }) //组件上使用nextTick Vue.component('example', { template: '{{ message }}', data: function () { return { message: 'not updated' } }, methods: { updateMessage: function () { this.message = 'updated' console.log(this.$el.textContent) // => '没有更新' this.$nextTick(function () { console.log(this.$el.textContent) // => '更新完成' }) } } }) 过渡效果 用transition封装组件,添加过渡,需要有个name属性,会自动生成四个对应类(name为transition的name属性的值) name-enter——动画起点 name-enter-active——动画中点 name-leave——动画中点的下一帧(默认与上一帧相同) name-leave-active——动画终点 屏幕截图.jpg (这是Vue官网的图) css过渡(简单的transition)

hello

var app01=new Vue({ el:'#app-01', data:{ show:true } }) //css部分,设置对应类的动画 .fade-enter-active,.fade-leave-active{ transition: opacity 3s; } .fade-enter, .fade-leave-active{ opacity: 0 } css动画(animation) //代码虽然多,但是信息量并不大 //css部分 .bounce-enter-active{ animation: bounce-in 1s } .bounce-leave-active{ animation: bounce-out 1s } //这里给p设了一个背景色,还设了一个50%的宽度,是为了观测scale的动画效果 p{ background-color: red; width:50%; } @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) } } //html部分

look at me

//js部分 var app02=new Vue({ el:'#app-02', data:{ show:true } }) 与css过渡的区别:‘在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。’(存疑) 自定义过渡类名:结合其他第三方动画库等使用 enter-class enter-active-class leave-class leave-active-class //用法

look at me

使用js钩子,enter和leave各自有4个钩子: beforeEnter——一些预设 enter——进入动画,部分情况需要有回调函数 afterEnter enterCancelled beforeLeave leave——离开动画,部分情况需要有回调函数 afterLeave leaveCancelled 注:只用js过渡时,enter和leave中的回调函数是必须的,不然动画会立即完成。对于仅适用js过渡的元素,最好添加v-bind:css="false"避免过渡中css的影响 //引入一个velocity库,便于操作dom属性

demo

var app03=new Vue({ el:'#app-03', data:{ show:false }, methods:{ beforeEnter:function(el){ el.style.opacity = 0 //预设了旋转中心点是左侧 el.style.transformOrigin='left' }, enter:function(el,done){ //字体由初始变为1.4em,耗时300毫秒 Velocity(el, {opacity:1,fontSize:'1.4em'}, {duration:300}) //字体变回1em,并变为静止状态 Velocity(el,{fontSize:'1em'},{complete:done}) }, leave:function(el,done){ //结束动作分为三步:先是旋转50度,x轴偏移15pxs是为了使旋转看起来更自然,并设了600毫秒的时间 Velocity(el,{translateX:'15px',rotateZ:'50deg'},{duration:600}) //第二步:旋转了100度,循环2次 Velocity(el,{rotateZ:'100deg'},{loop:2}) //第三次旋转45度,并结束 Velocity(el,{ rotateZ:'45deg', translateX:'30px', translateY:'30px', opacity:0 },{complete:done}) } } }) rotateZ——3d旋转,绕z轴旋转 translateX——x轴变化 translateY——y轴变化 transformOrigin——变化旋转元素的基点(圆心) 初始渲染的过渡 这里例子没效果,(存疑) .custom-appear-class{ font-size: 40px; color: red; background: green; } .custom-appear-active-class{ background: green; }

demo

var app03=new Vue({ el:'#app-03', data:{ show:true } }) 多个元素的过渡 用v-if/v-else来控制过渡

Sorry, no items found.

但是需要注意,当两个过渡元素标签名相同时,需要设置key值来区分,否则Vue会自动优化为,只替换内容,那么就看不到过渡效果了 先来个过渡的例子: //html部分,设定了两个button,并用toggle来切换值,为了避免Vue的只替换内容,设了两个不同的key值

//css部分 //首先是对过渡元素进行绝对定位,不然过渡过程中,元素共同出现时位置会有奇怪的问题(这个限定有点麻烦) #app-04 button{ position: absolute; left:100px; } //参考案例,button进入有个动画,取名move_in .try-enter-active{ animation: move_in 1s; } //动画包含了位移,从右侧到中间,透明度从0到1 @keyframes move_in{ from{left:150px;opacity: 0} to{left:100px;opacity: 1} } //button出去的动画取名move_out .try-leave-active{ animation:move_out 1s; //同move_in @keyframes move_out{ from{left:100px;opacity: 1} to{left:50px;opacity: 0} } //js部分 var app04=new Vue({ el:'#app-04', data:{ isEditing:true } }) 多种方法设置不同标签的过渡: 通过给同一个元素的key特性设置不同的状态来代替v-if/v-else(这个好棒): 把v-if升级为switch,实现不止2个标签的绑定: computed: { buttonMessage: function () { switch (docState) { case 'saved': return 'Edit' case 'edited': return 'Save' case 'editing': return 'Cancel' } } } vue还提供了过渡模式,两种,in-out和out-in,用法: 算是过渡控制增强 多组件过渡 :动态组件component绑定 //css部分 .component-fade-enter-active,.component-fade-leave-active{ transition:opacity .5s ease; } .component-fade-enter,.component-fade-leave-active{ opacity: 0; } //html部分

//设置了out-in后组件可以不用考虑绝对定位的问题了
//js部分 var app05=new Vue({ el:'#app-05', data:{ view:'v-a' }, components:{ 'v-a':{ template:'
Component A
' }, 'v-b':{ template:'
Component B
' } } }) 列表过渡 使用transition-group,必须对子项设置特定的key名 进入离开过渡 //css部分 #app-06 p{ width: 100% } #app-06 span{ //把display设置成inline-block,才可以设置它的translateY,不然没有位移效果 display: inline-block; margin-right: 10px; } .list-enter-active,.list-leave-active{ transition: all 1s; } .list-enter,.list-leave-active{ opacity: 0; //两种写法,一种是如下,另一种是translateY(30px) transform: translate(0px,30px); } //html部分
{{item}}
//js部分 var app06=new Vue({ el:'#app-06', data:{ items:[1,2,3,4,5,6,7,8,9], nextNum:10 }, methods:{ randomIndex:function(){ return Math.floor(Math.random()*this.items.length) }, //复习一下splice(a,b,c),a:待增加/删除的项目,b:删除的项目数,c:待增加的项目(可不止一个) add:function(){ this.items.splice(this.randomIndex(),0,this.nextNum++) }, remove:function(){ this.items.splice(this.randomIndex(),1) } } }) 列表的位移过渡 使用新增的v-move特性,它会在元素的改变定位的过程中应用,vue内部是使用了一个叫FLIP的动画队列。 //css部分 //这里对name-move设了一个transition,就可以控制位移过程中的动画效果 .shuffle-list-move{ transition: transform 1s; } //html部分
  • {{item}}
  • //js部分 var app07=new Vue({ el:'#app-07', data:{ items:[1,2,3,4,5,6,7,8,9] }, methods:{ //教程中是引用了lodash的方法库,让我们自己写这个洗牌算法吧(Fisher-Yates shuffle) shuffle:function(){ let m=this.items.length, t,i; while(m){ i=Math.floor(Math.random()*m--); t=this.items[i]; this.items.splice(i,1,this.items[m]); this.items.splice(m,1,t); } } } }) 进入离开过渡和位移过渡的组合版: //css部分 #app-06 p{ width: 100% } #app-06 span{ display: inline-block; margin-right: 10px; transition: all 1s; } .list-enter,.list-leave-active{ opacity: 0; transform: translate(0px,30px); } //需要重点注意的是这里:离开动画需要设置一个绝对定位,不然离开动画不圆滑,原因不明(存疑) .list-leave-active{ position: absolute; } .list-move{ transition: transform 1s; } //html部分
    {{item}}
    //js部分 var app06=new Vue({ el:'#app-06', data:{ items:[1,2,3,4,5,6,7,8,9], nextNum:10 }, methods:{ randomIndex:function(){ return Math.floor(Math.random()*this.items.length) }, add:function(){ this.items.splice(this.randomIndex(),0,this.nextNum++) }, remove:function(){ this.items.splice(this.randomIndex(),1) }, shuffle:function(){ let m=this.items.length, t,i; while(m){ i=Math.floor(Math.random()*m--); t=this.items[i]; this.items.splice(i,1,this.items[m]); this.items.splice(m,1,t); } } } }) 列表升级版——矩阵例子 //css部分 //由于shuffle是整个矩阵混排,所以其实是一个长度为81的列表的混排,矩阵的位置由css的flex来确定 //父元素规定为flex,规定长度,并定义了超出长度时的换行方式 .cellContainer{ display: flex; flex-wrap: wrap; width: 238px; margin-top: 10px; } //子元素规定为flex,规定长宽,横向对齐方式,纵向对齐方式,为了视觉好看,重合部分的边需要去重。 .cell{ display: flex; justify-content: space-around; align-items: center; width: 25px; height: 25px; border: 1px solid #aaa; margin-right: -1px; margin-bottom: -1px; } .shuffle-table-move{ transition: transform 1s; } //html部分
    {{cell.number}}
    //js部分 var app08=new Vue({ el:'#app-08', data:{ //数组方法,先是创建一个有81项的数组,内容为null,然后用map方法返回每个数组项,包含id和number两个属性 cells:Array.apply(null,{length:81}) .map(function(_,index){ return{ id:index, number:index%9+1 } }) }, methods:{ shuffle:function(){ let m=this.cells.length, t,i; while(m){ i=Math.floor(Math.random()*m--); t=this.cells[i]; this.cells.splice(i,1,this.cells[m]); this.cells.splice(m,1,t); } } } }) 列表的渐进过渡 核心思想是设置一个定时器,根据index设置不同的位移序列,从而形成渐进
    //:css禁止css的影响 //监听事件:before-enter/enter/leave
  • {{item.msg}}
  • var app09=new Vue({ el:'#app-09', data:{ //原始列表 query:'', list:[ {msg:'Bruce Lee'}, {msg:'Jackie Chan'}, {msg:'Chuck Norris'}, {msg:'Jet Li'}, {msg:'Kung Fury'} ] }, computed:{ //复合列表,用了一个过滤器,返回查找query不为空的选项 computedList:function(){ var vm=this return this.list.filter(function(item){ return item.msg.toLowerCase().indexOf(vm.query.toLowerCase())!==-1 }) } }, methods:{ beforeEnter:function(el){ el.style.opacity=0 el.style.height=0 }, //设置一个delay时间,根据参数值而不同 enter:function(el,done){ var delay=el.dataset.index*150 setTimeout(function(){ Velocity(el,{opacity:1,height:'1.6em'},{complete:done}) },delay) }, leave:function(el,done){ var delay=el.dataset.index*150 setTimeout(function(){ Velocity(el,{opacity:0,height:0},{complete:done}) },delay) } } }) h5自定义属性dataset用法: html中自定义属性:
    js中引用属性: var div =document.getElementById(''example") console.log(div.dataset.pro) //我是pro 注意两者的小差异,html中是data-name,js中引用时需要写为dataset.name 可复用的过渡 这里提到了函数式组件,需要看完后面的render函数来结合使用 动态过渡 过渡的数据可以动态控制,用js来获取
    //input type="range"是滑动条,把值绑定到fadeInDuation Fade In Fade Out //这里有一个对show值的判断,这是控制淡入淡出循环的关键

    hello

    var app10=new Vue({ el:'#app-10', data:{ show:true, fadeInDuation:1000, fadeOutDuation:1000, maxFadeDuration:1500, stop:false }, mounted:function(){ this.show=false }, methods:{ beforeEnter:function(el){ el.style.opacity=0 }, enter:function(el,done){ var vm=this Velocity(el,{opacity:1},{duration:this.fadeInDuation,complete:function(){ done() if(!vm.stop) vm.show=false }}) }, leave:function(el,done){ var vm=this Velocity(el,{opacity:0},{duration:this.fadeOutDuation,complete:function(){ done() vm.show=true }}) } } }) 注意问题: 1、初始show设置为true,mounted钩子里又改为false,而enter和leave中又分别对show有更新,为什么这么复杂? :测试发现,初始第一次渲染,并不会触发enter事件,而是默认渲染(无语),如果没有mounted钩子的show=false,则无法触发leave事件,元素会停留在初始渲染状态,不会自循环,所以整个循环是从mounted触发leave事件开始的,leave事件又把show=true,转而触发enter事件,enter事件show=false,又触发leave,从而形成循环 2、之前都没太注意Velocity前的那句var vm=this,原因是进入Velocity函数后,在done语句之后,this就不是Vue自己的this了,所以需要存值,done之前的目测还可以用 过渡状态 状态动画与watcher

    {{animatedNumber}}

    var app01=new Vue({ el:'#app-01', data:{ number:0, animatedNumber:0 }, watch:{ number:function(newValue,oldValue){ var vm=this function animate(time){ requestAnimationFrame(animate) TWEEN.update(time) } new TWEEN.Tween({tweeningNumber:oldValue}) .easing(TWEEN.Easing.Quadratic.Out) .to({tweeningNumber:newValue},1000) .onUpdate(function(){ vm.animatedNumber=this.tweeningNumber.toFixed(0) }) .start() animate() } } }) 注意问题 1、百度搜tweenjs,出来的那个creatjs并不是教程里引用的库,google的是:git仓库地址 研究了一圈用法,发现用法很基本,很固定: 创建一个tween对象,并传入起始对象:new TWEEN.Tween(起始对象) (此项非必须)变化曲线方程:easing(曲线方程),官方提供了31种 to(终点对象,时间) (此项非必须但此案例必须)onUpdate(函数),此案例中就是每次变化,都要执行函数,从而才形成动画效果 start()开始 重点来了,tween并不会自启动,需要用update()来启动,官方也建议加一个requestAnimationFrame,以平滑动画,防止掉帧,于是出现了啰嗦但是必须的animate()函数。 2、上文提到的requestAnimationFrame,字面意思是“请求动画帧”,它的用途张鑫旭大神已经详细说明,附链接:张鑫旭博客,概括说明是,requestAnimationFrame(内容)在下一帧执行动画,与setTimeout的区别是不会掉帧。 3、v-model.number="number"我愣了一下,后来发现是后缀标记,表示把v-model绑定值转化为数字 进化版,引入颜色渐变动画 //引入新库,color.js //对色块样式简单定义 //html部分
    //v-on:keyup.enter="updateColor"是绑定一个键盘按键,.enter是13键的别名

    Preview:

    //把样式绑定到tweenedCSSColor

    {{tweenedCSSColor}}

    //js部分 //又见命名空间,作者叫brehaut var Color=net.brehaut.Color var app02=new Vue({ el:'#app-02', data:{ colorQuery:'', //注意color是一个包含4个属性的对象 color:{ red:0, green:0, blue:0, alpha:1 }, tweenedColor:{} }, //这里用了一个原生js的方法,Object.assign(目标对象,源对象),是将源对象的可枚举属性复制进目标对象内,按值复制,返回目标对象,一般用于合并多个对象,此例中只有一个对象,改为this.tweenedColor=this.color也是ok的,或者不用created钩子,在data内初始化tweenedColor也ok created:function(){ this.tweenedColor=Object.assign({},this.color) }, //watch很有用,每当color值有变化,都会触发这个函数 watch:{ color:function(){ function animate(time){ requestAnimationFrame(animate) TWEEN.update(time) } //这里,tweenedColor也会被更新掉 new TWEEN.Tween(this.tweenedColor) .to(this.color,750) .start() animate() } }, computed:{ //这里用了color.js的一个方法,toCSS(),是把color形式的对象转化为可用的"#123456"的颜色字符串 tweenedCSSColor:function(){ return new Color({ red:this.tweenedColor.red, green:this.tweenedColor.green, blue:this.tweenedColor.blue, alpha:this.tweenedColor.alpha }).toCSS() } }, methods:{ updateColor:function(){ //使用了color.js的一个方法toRGB(),创建新的color对象,传入有效值,转化为color格式的对象并返回 this.color=new Color(this.colorQuery).toRGB() //这一句是清空了input的上一次输入,可有可无,去掉的话input内会保持上一次输入的值 this.colorQuery='' } } }) 总结 1、color.js用到的方法: 创建新的color对象并转成color格式{red:1,green:2,blue:3,alpha:1}:new Color(有效值).toRGB() 转成#123456格式:new Color(有效值).toCSS() 动态状态转换 //css部分 #app-03 svg,#app-03 input{ display: block; } //polygon的填色方式不同于其他css语法,用的是fill #app-03 polygon{ fill:#41b883; } //stroke控制边的样式 #app-03 circle{ fill:transparent; stroke: #35495e; } #app-03 input{ width: 90%; margin-bottom: 15px; } //html部分
    //js部分 var app03=new Vue({ el:'#app-03', data:function(){ var defaultSides=10 var stats=Array.apply(null,{length:defaultSides}).map(function(){return 100}) return { stats:stats, points:generatePoints(stats), sides:defaultSides, minRadius:50, interval:null, updateInterval:500 } }, watch:{ //这里有个好玩的问题,参考fiddle上的例子,是用了一个for循环来添加删改stats,但是我想啊,watch作为监控,应该是每次sides有变化就会触发,而sides本身又是一个滑条,那么数值必然是依次变化的,所以可否取消for循环,只判断新旧值,每次只添加删除一项。 //但是通过console.log(newSides-oldSides)发现,滑动太快的话,就会输出2啊3啊什么的,这可能和浏览器读取还有watch的监控机制有关 //于是只好乖乖改为for循环了 sides:function(newSides,oldSides){ var sidesDifference = newSides - oldSides if (sidesDifference > 0) { this.stats.push(this.newRandomValue()) } else { this.stats.shift() } }, //咦,引用了一个新的缓动库,感觉这个库好用多了,是著名的Greensock绿袜子 stats:function(newStats){ TweenLite.to( this.$data, this.updateInterval/1000, {points:generatePoints(newStats)}) }, updateInterval:function(){ this.resetInterval() } }, //清掉这个能看到预设的初始状态 mounted:function(){ this.resetInterval() }, methods:{ randomizeStats:function(){ var vm=this this.stats=this.stats.map(function(){ return vm.newRandomValue() }) }, newRandomValue:function(){ return Math.ceil(this.minRadius+Math.random()*(100-this.minRadius)) }, resetInterval:function(){ var vm=this clearInterval(this.interval) this.randomizeStats() this.interval=setInterval(function(){ vm.randomizeStats() },this.updateInterval) } } }) function valueToPoint(value,index,total){ var x=0,y=-value*0.9,angle=Math.PI*2/total*index,cos=Math.cos(angle),sin=Math.sin(angle),tx=x*cos-y*sin+100,ty=x*sin+y*cos+100 return {x:tx,y:ty} } function generatePoints(stats){ var total=stats.length return stats.map(function(stat,index){ var point=valueToPoint(stat,index,total) return point.x+','+point.y }).join(' ') } 注意问题: 1、用了svg多边形和圆,多边形传入点的参数,点的参数格式为{x,y x,y} 2、引用了一个新库,叫TweenLite.js,还有一个系列的动画库,简单好用 3、data返回了一个函数,是为了不同实例不共享数据 4、sides监控处出现一个想当然的问题,见代码解释 5、动画的循环是通过resetInterval中的定时器实现的,动画的渐变是监控了stats的变化。 render函数 第一个例子
    Hello world!
    Vue.component('anchored-heading',{ render:function(createElement){ return createElement( 'h'+this.level, this.$slots.default) }, props:{ level:{ type:Number, required:true } } }) var app01=new Vue({ el:'#app-01', data:{ level:'' } }) 完整例子
    hello world
    //创建一个查找并递归子文本的函数 var getChildrenTextContent=function (children){ return children.map(function(node){ return node.children?getChildrenTextContent(node.children):node.text }).join('') } Vue.component('anchored-heading',{ render:function(createElement){ var headingId=getChildrenTextContent(this.$slots.default) .toLowerCase() //把非字符替换成'-' .replace(/W+/g,'-') //把开头结尾的‘-’替换为空 .replace(/(^-|-$)/g,'') return createElement( 'h'+this.level, [ createElement('a',{ attrs:{ name:headingId, href:'#'+headingId } },this.$slots.default) ] ) }, props:{ level:{ type:Number, required:true } } }) var app01=new Vue({ el:'#app-01', data:{ level:'' } }) 深入分析createElement() 三部分组成: 标签名,必须,此例中是'h'+this.level和'a' data object参数,不是必须的,{},即各种属性设定,class/style/attrs/props/domProps/on/nativeOn/directives/scopedSlots/slot/key/ref(class和style级别最高) 子节点或者内容,必须,如果是子节点,因为不止一个,所以需要加一个[]表示为数组形式,(但是每个子元素必须唯一)子节点就是嵌套的createElement(),如果是内容,直接就是字符串,例子是,this.$slots.default。 render的形式 render:function(createElement){ 一些预操作 return createElement(组成内容) 使用js来代替模板功能 v-if&v-for变为原生的if/else&for(map)
    Vue.component('component-vif',{ props:["items"], //由于items使用了map和length,所以应该为一个数组对象,且包含name属性 render:function(createElement){ if(this.items.length){ return createElement('ul',this.items.map(function(item){ return createElement('li',item.name) })) } else{ return createElement('p','No items found.') } } }) var app01=new Vue({ el:'#app-01', data:{ level:'1', items:[ {name:'aaa'}, {name:'bbb'} ] } }) v-model要自己实现相应逻辑
    Vue.component('component-vmodel',{ render:function(createElement){ var self=this return createElement('p',[ createElement('input',{ domProps:{ value:self.value, }, on:{ input:function(event){ self.value=event.target.value } } }), createElement('span',self.value) ]) }, props:['orivalue'], data:function(){ var value=this.orivalue return {value} } }) var app01=new Vue({ el:'#app-01', data:{ level:'1', items:[ {name:'aaa'}, {name:'bbb'} ], value:'' } }) 注意问题 由于存在对组件内value赋值的问题,第一次只有prop没有data的时候,后台友好提示,“Avoid mutating a prop directly since the value will be overwritten”,于是加一个data进行一次赋值,这里用了函数式data 原例子中组件只有一个input元素,然而怎么看出来绑定成功没有呢?我加了一个span来看值的对应修改,这里发现,属性上domProps下设置innerHTML和第三项上内容绑定,目测没什么区别嘛 事件&按键修饰符 ** .capture/.once**——对应!/~,可组合 capture是捕获的意思,capture模式是捕获阶段触发回调,区别于默认的冒泡阶段,这个解释segmentfault上有个很好的例子 其他修饰符没前缀,可以自己使用事件方法: .stop——event.stopPropagation()停止传播 .prevent——event.preventDefault()阻止默认行为 .self——if(event.target==event.currentTarget) return 限定触发事件的是事件本身,target是事件目标,currentTarget是当前对象(父级) .enter(13)——if(event.keyCode!==13)return .ctrl/.alt/.shift/.meta——if(event.ctrlKey) return
    Vue.component('com-keymod',{ render:function(createElement){ var vm=this return createElement( 'div', { on:{ '!click':this.doThisInCapturingMode, '~mouseover':this.doThisOnceInCapturingModeOver, '~mouseleave':this.doThisOnceInCapturingModeLeave } }, [ createElement('input',{ on:{ keyup:function(event){ if(event.target!==event.currentTarget) this.value=1 if(!event.shiftKey||event.keyCode!==13) this.value=2 } } }), vm.value, this.$slots.default ] ) }, data:function(){ return {value:0} }, methods:{ doThisInCapturingMode:function(){ this.value=3 }, doThisOnceInCapturingModeOver:function(){ this.value+=1 }, doThisOnceInCapturingModeLeave:function(){ this.value-=1 } } }) var app01=new Vue({ el:'#app-01' }) - slots - 静态内容:this.$slots.default template:'
    ' 相当于: render:function(createElement){ return createElement('div',this.$slots.foo) } - 作用域slot,子组件 template:'
    ' 相当于: render:function(createElement){ return createElement('div',[ this.$scopedSlots.default({ text:this.msg })]) } - 作用域slot,父组件 template:'' 相当于: render:function(createElement){ return createElement('child',{ scopedSlots:{ default:function(props){ return createElement('span',props.text) } } }) } 学到此处,我默默回头复习了一下组件内slot部分 - JSX 为了把render内的语句写的更接近模板一点,可以用JSX语法,安装babel的插件实现 - 函数化组件 (存疑)例子有问题 - 模板编译:vue的模板实际是编译成了render函数 ####自定义指令 - 第一个简单例子,同样需要补充完整: 111 Vue.directive('focus',{ inserted:function(el){ el.focus() } }) var app01=new Vue({ el:'#app-01', //写在实例作用域内 /* directives:{ focus:{ inserted:function(el){ el.focus() } } } */ }) 类似于组件的写法,两种写法,一种是全局自定义指令,另一种是定义在实例作用域内部 - 钩子函数和函数参数
    var app02=new Vue({ el:'#app-02', data:{ message:"hello" }, directives:{ demo:{ bind:function(el,binding,vnode){ var s=JSON.stringify el.innerHTML= 'name:'+s(binding.name)+''+ 'value:'+s(binding.value)+''+ 'expression:'+s(binding.expression)+''+ 'argument:'+s(binding.arg)+''+ 'modifiers:'+s(binding.modifiers)+''+ 'vnode keys:'+Object.keys(vnode).join(',') } } } }) 钩子函数有: - bind:只调用一次,指令第一次绑定到元素时调用 - inserted:被绑定元素插入父节点时调用(父节点存在即可调用) - update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。 - componentUpdated:被绑定元素所在模板完成一次更新周期时调用 - unbind:只调用一次,指令与元素解绑时调用 钩子函数参数有: - el:指令所绑定的元素 - binding:一个对象,包含以下属性: - name:指令名(不含v-前缀) - value:指令的绑定值(计算后的) - expression:绑定值的字符串形式 - oldValue:指令绑定的前一个值 - arg:传给指令的参数 - modifiers:一个包含修饰符的对象 - vnode:Vue编译生成的虚拟节点 - oldValue:上一个虚拟节点 - 函数简写: 如果只想用bind和update钩子,可以省略钩子名称这一步,直接写: //这是实例内directives内 swatch:function(el,binding,vnode){ el.style.backgroundColor=binding.value } - 对象字面量 之前的例子都是传入对象名称,比如:
    111
    var app02=new Vue({ el:'#app-02', data:{ message:"hello", color:'#123456' }, directives:{ swatch:function(el,binding,v){ el.style.backgroundColor=binding.value } } }) 也可以直接传入一个js对象字面量,比如:
    111
    var app02=new Vue({ el:'#app-02', data:{ message:"hello" }, directives:{ swatch:function(el,binding,v){ //注意这里,因为传入的是一个对象,因此需要在value后面加上对象属性,才能索引到对应的值 el.style.backgroundColor=binding.value.color } } }) ####混合 - 第一个简单例子: //定义一个混合对象 var myMixin = { created:function(){ this.hello() }, methods:{ hello:function(){ console.log('hello from mixin!') } } } var Component = Vue.extend({ mixins:[myMixin] }) var component=new Component() >这个例子中出现了不熟悉的语句,于是我决定去复习一下组件的创建和注册 - 首先,平常的组件创建,都是直接注册的,使用的以下形式 Vue.component("name","arg") 这其实是把两个步骤合为一个步骤 - 步骤一,创建组件构造器 //这是Vue构造器的扩展,创建了一个组件构造器 var a=Vue.extend(各种参数,比如template) - 步骤二,注册组件 Vue.component("name","组件构造器(a)") 所以平时输入的arg其实就是一个组件构造器,在需要复用组件的组成的时候,就可以把arg拆出来复用一下 - 创建——注册——挂载,组件使用的三步骤: - 最常见:创建和注册同时完成,挂载利用其它vue实例,在其内部使用
    //创建+注册 Vue.component("mycom",{ 我是组件构造器的内容 }) //利用其它vue实例实现挂载 var app01=new Vue({ el:'#app-01' }) - 不注册也存在:不注册组件,只创建,通过实例化,后台可以看到console语句 mycom=Vue.extend({ 我是组件构造器的内容 }) new mycom() >回到开始的例子,首先定义了一个混合对象myMixinm,然后定义了一个组件构造器,命名为Component,然后用这个构造器创建了一个实例,由于没有挂载,也没注册组件,所以只能后台看到它确实存在 - 选项合并和优先性: - 同名钩子函数将被合并为一个数组,混合对象的钩子优先调用 var myMixin = { template:'

    2222

    ', created:function(){ this.hello() }, methods:{ hello:function(){ console.log('hello from mixin!') } } } var customcom = Vue.extend({ created:function(){ console.log("hello from component") }, mixins:[myMixin] }) new customcom() //hello from mixin! //hello from component - 值为对象的选项,将被合并为同一个对象,键名冲突时,取组件对象的键值对: var myMixin = { methods:{ hello:function(){ console.log('hello from mixin!') }, foo:function(){ console.log('foo') } } } var customcom = Vue.extend({ methods:{ hello:function(){ console.log('hello from component!') }, bar:function(){ console.log('bar') } }, mixins:[myMixin] }) var vm=new customcom() vm.foo() vm.bar() vm.hello() //foo //bar //hello from component! - 全局注册混合对象:会影响所有之后创建的Vue实例,慎用: Vue.mixin({ template:'

    222

    ', created:function(){ var myOption=this.$options.myOption if(myOption){ console.log(myOption) } } }) var app01=new Vue({ el:'#app-01', myOption:'hello!' }) //页面:222 //后台:hello! - 自定义选项的混合策略:默认是覆盖已有值 var myMixin = { myOption:"hello from mixin!" } var customcom = Vue.extend({ myOption:"hello from vue!", created:function(){ var myOption=this.$options.myOption if(myOption){ console.log(myOption) } }, mixins:[myMixin] }) new customcom() //hello from vue 修改的方式没测试出来(存疑) ####插件 - vue-element - vue-touch - vuex - vue-router 社区:[awesome-vue](https://github.com/vuejs/awesome-vue#libraries--plugins) *** 接下来的内容需要结合webpack和vue的插件,进阶部分到此结束啦 11111111111 1111111111111111111 111111111111111 1111111111111111 1111111111111111 1111111111111111 1111111111111 1111111111111111 1111111111111111 111111111111111111 111111111111111111 111111111111111 11111111111111111 111111111111111111 11111111111111111 111111111111111111 11111111111111111 11111111111111111 11111111111
    作文投稿

    种子的希望一文由杰瑞文章网免费提供,本站为公益性作文网站,此作文为网上收集或网友提供,版权归原作者所有,如果侵犯了您的权益,请及时与我们联系,我们会立即删除!

    杰瑞文章网友情提示:请不要直接抄作文用来交作业。你可以学习、借鉴、期待你写出更好的作文。

    种子的希望相关的作文:

      无相关信息

    说说你对这篇作文的看法吧