Vue.js學(xué)習(xí)筆記-進(jìn)階部分+完整實(shí)現(xiàn)代碼

深入響應(yīng)式

  • 追蹤變化:

把普通js對(duì)象傳給Vue實(shí)例的data選項(xiàng),Vue將使用Object.defineProperty把屬性轉(zhuǎn)化為getter/setter(因此不支持IE8及以下),每個(gè)組件實(shí)例都有相應(yīng)的watcher實(shí)例對(duì)象,它把屬性記錄為依賴,當(dāng)依賴項(xiàng)的setter被調(diào)用的時(shí)候,watcher會(huì)被通知并重新計(jì)算,從而更新渲染

  • 變化檢測(cè):

  • Vue不能檢測(cè)到對(duì)象屬性的添加或刪除,因此屬性必須在data對(duì)象上存在才能讓Vue轉(zhuǎn)換它,才是響應(yīng)式的

  • Vue不允許在已經(jīng)創(chuàng)建的實(shí)例上動(dòng)態(tài)添加新的根級(jí)響應(yīng)式屬性,但是可以將響應(yīng)屬性添加到嵌套的對(duì)象上,使用Vue.set(object,key,value)

Vue.set(vm.someObject,'b',2)

還可以用vm.$set實(shí)例方法,是Vue.set的別名:

this.$set(this.someObject,'b',2)

想向已有對(duì)象添加一些屬性,可以創(chuàng)建一個(gè)新的對(duì)象,讓它包含原對(duì)象的屬性和新屬性:

this.someObject=Object.assign({},this.someObject,{a:1,b:2})
  • 聲明響應(yīng)式屬性:由于不允許動(dòng)態(tài)添加根級(jí)響應(yīng)式屬性,所以初始化實(shí)例前要聲明,即便是個(gè)空值:
var vm = new Vue({
  data: {
    // 聲明 message 為一個(gè)空值字符串
    message: ''
  },
  template: '<div>{{ message }}</div>'
})
// 之后設(shè)置 `message` 
vm.message = 'Hello!'
  • Vue是異步更新隊(duì)列的,目的是緩沖同一個(gè)事件循環(huán)中所有數(shù)據(jù)變化去除重復(fù)數(shù)據(jù),但是問(wèn)題來(lái)了,當(dāng)設(shè)置數(shù)據(jù)變化時(shí),并不會(huì)立即重新渲染,需要排隊(duì),可是如果想要在這個(gè)變化后緊接著做點(diǎn)什么,就需要一個(gè)Vue.nextTick(callback)來(lái)表明,這個(gè)更新后再執(zhí)行操作:
<div id="example">{{message}}</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: '123'
  }
})
vm.message = 'new message' // 更改數(shù)據(jù)
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
})
//組件上使用nextTick
Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: 'not updated'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = 'updated'
      console.log(this.$el.textContent) // => '沒(méi)有更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '更新完成'
      })
    }
  }
})

過(guò)渡效果

用transition封裝組件,添加過(guò)渡,需要有個(gè)name屬性,會(huì)自動(dòng)生成四個(gè)對(duì)應(yīng)類(name為transition的name屬性的值)

  • name-enter——?jiǎng)赢?huà)起點(diǎn)
  • name-enter-active——?jiǎng)赢?huà)中點(diǎn)
  • name-leave——?jiǎng)赢?huà)中點(diǎn)的下一幀(默認(rèn)與上一幀相同)
  • name-leave-active——?jiǎng)赢?huà)終點(diǎn)
屏幕截圖.jpg

(這是Vue官網(wǎng)的圖)

css過(guò)渡(簡(jiǎn)單的transition)
<div id="app-01">
  <button v-on:click="show=!show">toggle</button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition> 
</div>
var app01=new Vue({
  el:'#app-01',
  data:{
    show:true
  }
})
//css部分,設(shè)置對(duì)應(yīng)類的動(dòng)畫(huà)
.fade-enter-active,.fade-leave-active{
      transition: opacity 3s;
    }
    .fade-enter, .fade-leave-active{
      opacity: 0
    }
css動(dòng)畫(huà)(animation)
//代碼雖然多,但是信息量并不大
//css部分
    .bounce-enter-active{
      animation: bounce-in 1s
    }
    .bounce-leave-active{
      animation: bounce-out 1s
    }
//這里給p設(shè)了一個(gè)背景色,還設(shè)了一個(gè)50%的寬度,是為了觀測(cè)scale的動(dòng)畫(huà)效果
    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部分
<div id="app-02">
  <button v-on:click="show=!show">toggle</button>
  <transition name="bounce">
    <p v-if="show">look at me</p>
  </transition> 
</div>
//js部分
var app02=new Vue({
  el:'#app-02',
  data:{
    show:true
  }
})

與css過(guò)渡的區(qū)別:‘在動(dòng)畫(huà)中 v-enter 類名在節(jié)點(diǎn)插入 DOM 后不會(huì)立即刪除,而是在 animationend 事件觸發(fā)時(shí)刪除。’(存疑)

  • 自定義過(guò)渡類名:結(jié)合其他第三方動(dòng)畫(huà)庫(kù)等使用
  • enter-class
  • enter-active-class
  • leave-class
  • leave-active-class
//用法
<transition name="bounce" 
  enter-active-class="animated tada"
  leave-active-class="animated bounceOutRight">
    <p v-if="show">look at me</p>
  </transition> 
  • 使用js鉤子,enter和leave各自有4個(gè)鉤子:
  • beforeEnter——一些預(yù)設(shè)
  • enter——進(jìn)入動(dòng)畫(huà),部分情況需要有回調(diào)函數(shù)
  • afterEnter
  • enterCancelled
  • beforeLeave
  • leave——離開(kāi)動(dòng)畫(huà),部分情況需要有回調(diào)函數(shù)
  • afterLeave
  • leaveCancelled

注:只用js過(guò)渡時(shí),enter和leave中的回調(diào)函數(shù)是必須的,不然動(dòng)畫(huà)會(huì)立即完成。對(duì)于僅適用js過(guò)渡的元素,最好添加v-bind:css="false"避免過(guò)渡中css的影響

//引入一個(gè)velocity庫(kù),便于操作dom屬性
<script src="vue/velocity.min.js"></script>
<div id="app-03">
  <button v-on:click="show=!show">toggle</button>
  <transition
//綁定一個(gè)beforeEnter函數(shù),用來(lái)預(yù)設(shè)狀態(tài)
  v-on:before-enter="beforeEnter"
//這是進(jìn)入動(dòng)畫(huà)
  v-on:enter="enter"
//這是離開(kāi)動(dòng)畫(huà)
  v-on:leave="leave"
//排除css影響
  v-bind:css="false" 
  >
    <p v-if="show">demo</p>
  </transition> 
</div>
var app03=new Vue({
  el:'#app-03',
  data:{
    show:false
  },
  methods:{
    beforeEnter:function(el){
      el.style.opacity = 0
//預(yù)設(shè)了旋轉(zhuǎn)中心點(diǎn)是左側(cè)
      el.style.transformOrigin='left'
    },
    enter:function(el,done){
//字體由初始變?yōu)?.4em,耗時(shí)300毫秒
      Velocity(el,
        {opacity:1,fontSize:'1.4em'},
        {duration:300})
//字體變回1em,并變?yōu)殪o止?fàn)顟B(tài)
      Velocity(el,{fontSize:'1em'},{complete:done})
    },
    leave:function(el,done){
//結(jié)束動(dòng)作分為三步:先是旋轉(zhuǎn)50度,x軸偏移15pxs是為了使旋轉(zhuǎn)看起來(lái)更自然,并設(shè)了600毫秒的時(shí)間
      Velocity(el,{translateX:'15px',rotateZ:'50deg'},{duration:600})
//第二步:旋轉(zhuǎn)了100度,循環(huán)2次
      Velocity(el,{rotateZ:'100deg'},{loop:2})
//第三次旋轉(zhuǎn)45度,并結(jié)束
      Velocity(el,{
        rotateZ:'45deg',
        translateX:'30px',
        translateY:'30px',
        opacity:0
      },{complete:done})
    }
  }
})
  • rotateZ——3d旋轉(zhuǎn),繞z軸旋轉(zhuǎn)
  • translateX——x軸變化
  • translateY——y軸變化
  • transformOrigin——變化旋轉(zhuǎn)元素的基點(diǎn)(圓心)
初始渲染的過(guò)渡

這里例子沒(méi)效果,(存疑)

.custom-appear-class{
    font-size: 40px;
    color: red;
    background: green;
}

.custom-appear-active-class{
    background: green;
}
<div id="app-03">
  <button v-on:click="show=!show">toggle</button>
  <transition
  appear
  appear-class="custom-appear-class"
  appear-active-class="custom-appear-active-class"
>
    <p v-if="show">demo</p>
  </transition> 
</div>
var app03=new Vue({
  el:'#app-03',
  data:{
    show:true
  }
})
多個(gè)元素的過(guò)渡
  • 用v-if/v-else來(lái)控制過(guò)渡
<transition>
  <table v-if="items.length > 0">
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>

但是需要注意,當(dāng)兩個(gè)過(guò)渡元素標(biāo)簽名相同時(shí),需要設(shè)置key值來(lái)區(qū)分,否則Vue會(huì)自動(dòng)優(yōu)化為,只替換內(nèi)容,那么就看不到過(guò)渡效果了

先來(lái)個(gè)過(guò)渡的例子:

//html部分,設(shè)定了兩個(gè)button,并用toggle來(lái)切換值,為了避免Vue的只替換內(nèi)容,設(shè)了兩個(gè)不同的key值
<div id="app-04">
<button v-on:click="isEditing=!isEditing">toggle</button>
<br>
  <transition name="try" mode="in-out">
    <button v-if="isEditing" key="save">
      in
    </button>
    <button v-else key="edit">out</button>
  </transition>
</div>
//css部分
//首先是對(duì)過(guò)渡元素進(jìn)行絕對(duì)定位,不然過(guò)渡過(guò)程中,元素共同出現(xiàn)時(shí)位置會(huì)有奇怪的問(wèn)題(這個(gè)限定有點(diǎn)麻煩)
#app-04 button{
  position: absolute;
  left:100px;
 }
//參考案例,button進(jìn)入有個(gè)動(dòng)畫(huà),取名move_in
.try-enter-active{
  animation: move_in 1s; 
 } 
//動(dòng)畫(huà)包含了位移,從右側(cè)到中間,透明度從0到1
 @keyframes move_in{
  from{left:150px;opacity: 0}
  to{left:100px;opacity: 1}
 }
//button出去的動(dòng)畫(huà)取名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
  }
})

多種方法設(shè)置不同標(biāo)簽的過(guò)渡:

  • 通過(guò)給同一個(gè)元素的key特性設(shè)置不同的狀態(tài)來(lái)代替v-if/v-else(這個(gè)好棒):
<transition>
  <button v-bind:key="isEditing">
    {{ isEditing ? 'Save' : 'Edit' }}
  </button>
</transition>
  • 把v-if升級(jí)為switch,實(shí)現(xiàn)不止2個(gè)標(biāo)簽的綁定:
<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
computed: {
  buttonMessage: function () {
    switch (docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}
  • vue還提供了過(guò)渡模式,兩種,in-out和out-in,用法:
<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
</transition>

算是過(guò)渡控制增強(qiáng)

多組件過(guò)渡 :動(dòng)態(tài)組件component綁定
//css部分
.component-fade-enter-active,.component-fade-leave-active{
  transition:opacity .5s ease;
 }
 .component-fade-enter,.component-fade-leave-active{
  opacity: 0;
 }
//html部分
<div id="app-05">
  <button v-on:click="view=='v-a'?view='v-b':view='v-a'">toggle</button>
  <br>
//設(shè)置了out-in后組件可以不用考慮絕對(duì)定位的問(wèn)題了
  <transition name="component-fade" mode="out-in">
    <component v-bind:is="view"></component>
  </transition>
</div>
//js部分
var app05=new Vue({
  el:'#app-05',
  data:{
    view:'v-a'
  },
  components:{
    'v-a':{
      template:'<div>Component A</div>'
    },
    'v-b':{
      template:'<div>Component B</div>'
    }
  }
})
列表過(guò)渡

使用transition-group,必須對(duì)子項(xiàng)設(shè)置特定的key名

  • 進(jìn)入離開(kāi)過(guò)渡
//css部分
#app-06 p{
  width: 100%
 }
 #app-06 span{
//把display設(shè)置成inline-block,才可以設(shè)置它的translateY,不然沒(méi)有位移效果
  display: inline-block;
  margin-right: 10px;
 }
 .list-enter-active,.list-leave-active{
  transition: all 1s;
 }
 .list-enter,.list-leave-active{
  opacity: 0;
//兩種寫(xiě)法,一種是如下,另一種是translateY(30px)
  transform: translate(0px,30px);
 }
//html部分
<div id="app-06">
  <button @click='add'>Add</button>
  <button @click='remove'>Remove</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" :key="item">
      {{item}}
    </span>
  </transition-group>  
</div>
//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)
    },
//復(fù)習(xí)一下splice(a,b,c),a:待增加/刪除的項(xiàng)目,b:刪除的項(xiàng)目數(shù),c:待增加的項(xiàng)目(可不止一個(gè))
    add:function(){
      this.items.splice(this.randomIndex(),0,this.nextNum++)
    },
    remove:function(){
      this.items.splice(this.randomIndex(),1)
    }
  }
})
  • 列表的位移過(guò)渡
    使用新增的v-move特性,它會(huì)在元素的改變定位的過(guò)程中應(yīng)用,vue內(nèi)部是使用了一個(gè)叫FLIP的動(dòng)畫(huà)隊(duì)列。
//css部分
//這里對(duì)name-move設(shè)了一個(gè)transition,就可以控制位移過(guò)程中的動(dòng)畫(huà)效果
.shuffle-list-move{
  transition: transform 1s;
 }
//html部分
<div id="app-07">
  <button @click='shuffle'>Shuffle</button>
  <transition-group name="shuffle-list" tag="ul">
    <li v-for="item in items" :key="item">
      {{item}}
    </li>
  </transition-group>  
</div>
//js部分
var app07=new Vue({
  el:'#app-07',
  data:{
    items:[1,2,3,4,5,6,7,8,9]
  },
  methods:{
//教程中是引用了lodash的方法庫(kù),讓我們自己寫(xiě)這個(gè)洗牌算法吧(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);
        }
    }
  }
})
  • 進(jìn)入離開(kāi)過(guò)渡和位移過(guò)渡的組合版:
//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);
 }
//需要重點(diǎn)注意的是這里:離開(kāi)動(dòng)畫(huà)需要設(shè)置一個(gè)絕對(duì)定位,不然離開(kāi)動(dòng)畫(huà)不圓滑,原因不明(存疑)
 .list-leave-active{
  position: absolute;
 }
 .list-move{
  transition: transform 1s;
 }
//html部分
<div id="app-06">
  <button @click='add'>Add</button>
  <button @click='remove'>Remove</button>
  <button @click='shuffle'>Shuffle</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" :key="item">
      {{item}}
    </span>
  </transition-group>  
</div>
//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);
      }
    }
  }
})
  • 列表升級(jí)版——矩陣?yán)?/li>
//css部分
//由于shuffle是整個(gè)矩陣混排,所以其實(shí)是一個(gè)長(zhǎng)度為81的列表的混排,矩陣的位置由css的flex來(lái)確定
//父元素規(guī)定為flex,規(guī)定長(zhǎng)度,并定義了超出長(zhǎng)度時(shí)的換行方式
.cellContainer{
  display: flex;
  flex-wrap: wrap;
  width: 238px;
  margin-top: 10px;
 }
//子元素規(guī)定為flex,規(guī)定長(zhǎng)寬,橫向?qū)R方式,縱向?qū)R方式,為了視覺(jué)好看,重合部分的邊需要去重。
 .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部分
<div id="app-08">
  <button @click='shuffle'>Shuffle</button>
  <transition-group name="shuffle-table" tag="div" class="cellContainer">
  <div v-for="cell in cells" :key="cell.id" class="cell">
  {{cell.number}}
  </div>
</div>
//js部分
var app08=new Vue({
  el:'#app-08',
  data:{
//數(shù)組方法,先是創(chuàng)建一個(gè)有81項(xiàng)的數(shù)組,內(nèi)容為null,然后用map方法返回每個(gè)數(shù)組項(xiàng),包含id和number兩個(gè)屬性
    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);
        }
    }
  }
})
  • 列表的漸進(jìn)過(guò)渡
    核心思想是設(shè)置一個(gè)定時(shí)器,根據(jù)index設(shè)置不同的位移序列,從而形成漸進(jìn)
<div id="app-09">
  <input type="text" v-model="query">
//:css禁止css的影響
//監(jiān)聽(tīng)事件:before-enter/enter/leave
  <transition-group name="staggered-fade" tag="ul" v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave"
    >
    <li v-for="(item,index) in computedList" v-bind:key="item.msg" v-bind:data-index="index">{{item.msg}}</li>
    </transition-group>
</div>
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:{
//復(fù)合列表,用了一個(gè)過(guò)濾器,返回查找query不為空的選項(xiàng)
    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
    },
//設(shè)置一個(gè)delay時(shí)間,根據(jù)參數(shù)值而不同
    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中自定義屬性:
    <div id="example" data-pro="我是pro"></div>
  • js中引用屬性:
    var div =document.getElementById(''example")
    console.log(div.dataset.pro)
    //我是pro
    注意兩者的小差異,html中是data-name,js中引用時(shí)需要寫(xiě)為dataset.name
可復(fù)用的過(guò)渡

這里提到了函數(shù)式組件,需要看完后面的render函數(shù)來(lái)結(jié)合使用

動(dòng)態(tài)過(guò)渡

過(guò)渡的數(shù)據(jù)可以動(dòng)態(tài)控制,用js來(lái)獲取

<div id="app-10">
//input type="range"是滑動(dòng)條,把值綁定到fadeInDuation
  Fade In<input type="range" v-model="fadeInDuation" min="0" v-bind:max="maxFadeDuration">
  Fade Out<input type="range" v-model="fadeOutDuation" min="0" v-bind:max="maxFadeDuration">
  <transition v-bind:css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave">
//這里有一個(gè)對(duì)show值的判斷,這是控制淡入淡出循環(huán)的關(guān)鍵
  <p v-if="show">hello</p>
  </transition>
  <button @click="stop=true">Stop it!</button>
</div>
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
      }})
    }
  }
})

注意問(wèn)題:
1、初始show設(shè)置為true,mounted鉤子里又改為false,而enter和leave中又分別對(duì)show有更新,為什么這么復(fù)雜?
:測(cè)試發(fā)現(xiàn),初始第一次渲染,并不會(huì)觸發(fā)enter事件,而是默認(rèn)渲染(無(wú)語(yǔ)),如果沒(méi)有mounted鉤子的show=false,則無(wú)法觸發(fā)leave事件,元素會(huì)停留在初始渲染狀態(tài),不會(huì)自循環(huán),所以整個(gè)循環(huán)是從mounted觸發(fā)leave事件開(kāi)始的,leave事件又把show=true,轉(zhuǎn)而觸發(fā)enter事件,enter事件show=false,又觸發(fā)leave,從而形成循環(huán)
2、之前都沒(méi)太注意Velocity前的那句var vm=this,原因是進(jìn)入Velocity函數(shù)后,在done語(yǔ)句之后,this就不是Vue自己的this了,所以需要存值,done之前的目測(cè)還可以用

過(guò)渡狀態(tài)
  • 狀態(tài)動(dòng)畫(huà)與watcher
<script src="vue/tween.js"></script>
<div id="app-01">
  <input type="number" v-model.number="number" step="20">
  <p>{{animatedNumber}}</p>
</div>
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()
    }
  }
})

注意問(wèn)題
1、百度搜tweenjs,出來(lái)的那個(gè)creatjs并不是教程里引用的庫(kù),google的是:git倉(cāng)庫(kù)地址
研究了一圈用法,發(fā)現(xiàn)用法很基本,很固定:

  • 創(chuàng)建一個(gè)tween對(duì)象,并傳入起始對(duì)象:new TWEEN.Tween(起始對(duì)象)
  • (此項(xiàng)非必須)變化曲線方程:easing(曲線方程),官方提供了31種
  • to(終點(diǎn)對(duì)象,時(shí)間)
  • (此項(xiàng)非必須但此案例必須)onUpdate(函數(shù)),此案例中就是每次變化,都要執(zhí)行函數(shù),從而才形成動(dòng)畫(huà)效果
  • start()開(kāi)始
  • 重點(diǎn)來(lái)了,tween并不會(huì)自啟動(dòng),需要用update()來(lái)啟動(dòng),官方也建議加一個(gè)requestAnimationFrame,以平滑動(dòng)畫(huà),防止掉幀,于是出現(xiàn)了啰嗦但是必須的animate()函數(shù)。

2、上文提到的requestAnimationFrame,字面意思是“請(qǐng)求動(dòng)畫(huà)幀”,它的用途張?chǎng)涡翊笊褚呀?jīng)詳細(xì)說(shuō)明,附鏈接:張?chǎng)涡癫┛?/a>,概括說(shuō)明是,requestAnimationFrame(內(nèi)容)在下一幀執(zhí)行動(dòng)畫(huà),與setTimeout的區(qū)別是不會(huì)掉幀。
3、v-model.number="number"我愣了一下,后來(lái)發(fā)現(xiàn)是后綴標(biāo)記,表示把v-model綁定值轉(zhuǎn)化為數(shù)字

  • 進(jìn)化版,引入顏色漸變動(dòng)畫(huà)
//引入新庫(kù),color.js
<script src="vue/color.js"></script>
//對(duì)色塊樣式簡(jiǎn)單定義
<style>
   #app-02 span{
    display: block;
    width:100px;
    height: 100px;
   } 
  </style>
//html部分
<div id="app-02">
//v-on:keyup.enter="updateColor"是綁定一個(gè)鍵盤(pán)按鍵,.enter是13鍵的別名
  <input v-model="colorQuery" v-on:keyup.enter="updateColor" placeholder="Enter a color">
  <button v-on:click="updateColor">Update</button>
  <p>Preview:</p>
//把樣式綁定到tweenedCSSColor
  <span v-bind:style="{backgroundColor:tweenedCSSColor}"></span>
  <p>{{tweenedCSSColor}}</p>
</div>
//js部分
//又見(jiàn)命名空間,作者叫brehaut
var Color=net.brehaut.Color
var app02=new Vue({
  el:'#app-02',
  data:{
    colorQuery:'',
//注意color是一個(gè)包含4個(gè)屬性的對(duì)象
    color:{
      red:0,
      green:0,
      blue:0,
      alpha:1
    },
    tweenedColor:{}
  },
//這里用了一個(gè)原生js的方法,Object.assign(目標(biāo)對(duì)象,源對(duì)象),是將源對(duì)象的可枚舉屬性復(fù)制進(jìn)目標(biāo)對(duì)象內(nèi),按值復(fù)制,返回目標(biāo)對(duì)象,一般用于合并多個(gè)對(duì)象,此例中只有一個(gè)對(duì)象,改為this.tweenedColor=this.color也是ok的,或者不用created鉤子,在data內(nèi)初始化tweenedColor也ok
  created:function(){
    this.tweenedColor=Object.assign({},this.color)
  },
//watch很有用,每當(dāng)color值有變化,都會(huì)觸發(fā)這個(gè)函數(shù)
  watch:{
    color:function(){
      function animate(time){
        requestAnimationFrame(animate)
        TWEEN.update(time)
      }
//這里,tweenedColor也會(huì)被更新掉
      new TWEEN.Tween(this.tweenedColor)
      .to(this.color,750)
      .start()
      animate()
    }
  },
  computed:{
//這里用了color.js的一個(gè)方法,toCSS(),是把color形式的對(duì)象轉(zhuǎn)化為可用的"#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的一個(gè)方法toRGB(),創(chuàng)建新的color對(duì)象,傳入有效值,轉(zhuǎn)化為color格式的對(duì)象并返回
      this.color=new Color(this.colorQuery).toRGB()
//這一句是清空了input的上一次輸入,可有可無(wú),去掉的話input內(nèi)會(huì)保持上一次輸入的值
      this.colorQuery=''
    }
  }  
})

總結(jié)
1、color.js用到的方法:

  • 創(chuàng)建新的color對(duì)象并轉(zhuǎn)成color格式{red:1,green:2,blue:3,alpha:1}:new Color(有效值).toRGB()

  • 轉(zhuǎn)成#123456格式:new Color(有效值).toCSS()

  • 動(dòng)態(tài)狀態(tài)轉(zhuǎn)換

//css部分
#app-03 svg,#app-03 input{
    display: block;
   }
//polygon的填色方式不同于其他css語(yǔ)法,用的是fill
   #app-03 polygon{
    fill:#41b883;
   }
//stroke控制邊的樣式
   #app-03 circle{
    fill:transparent;
    stroke: #35495e;
   }
   #app-03 input{
    width: 90%;
    margin-bottom: 15px;
   }
//html部分
<div id="app-03">
  <svg width="200" height="200">
    <polygon v-bind:points="points"></polygon>
    <circle cx="100" cy="100" r="90"></circle>
  </svg>
    <label>Sides: {{sides}}</label>
    <input type="range" min="3"  max="500" v-model.number="sides">
    <label>Minimum Radius: {{minRadius}}%</label>
    <input type="range" min="0"  max="90" v-model.number="minRadius">
    <label>Update Interval: {{updateInterval}} milliseconds</label>
    <input type="range" min="10"  max="2000" v-model.number="updateInterval"> 
</div>
//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:{
//這里有個(gè)好玩的問(wèn)題,參考fiddle上的例子,是用了一個(gè)for循環(huán)來(lái)添加刪改stats,但是我想啊,watch作為監(jiān)控,應(yīng)該是每次sides有變化就會(huì)觸發(fā),而sides本身又是一個(gè)滑條,那么數(shù)值必然是依次變化的,所以可否取消for循環(huán),只判斷新舊值,每次只添加刪除一項(xiàng)。
//但是通過(guò)console.log(newSides-oldSides)發(fā)現(xiàn),滑動(dòng)太快的話,就會(huì)輸出2啊3啊什么的,這可能和瀏覽器讀取還有watch的監(jiān)控機(jī)制有關(guān)
//于是只好乖乖改為for循環(huán)了
    sides:function(newSides,oldSides){     
      var sidesDifference = newSides - oldSides
      if (sidesDifference > 0) {
    this.stats.push(this.newRandomValue())       
      } else {
            this.stats.shift()  
      }
    },
//咦,引用了一個(gè)新的緩動(dòng)庫(kù),感覺(jué)這個(gè)庫(kù)好用多了,是著名的Greensock綠襪子
    stats:function(newStats){
      TweenLite.to(
        this.$data,
        this.updateInterval/1000,
        {points:generatePoints(newStats)})
    },
    updateInterval:function(){
      this.resetInterval()
    }
  },
//清掉這個(gè)能看到預(yù)設(shè)的初始狀態(tài)
  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(' ')
}

注意問(wèn)題:
1、用了svg多邊形和圓,多邊形傳入點(diǎn)的參數(shù),點(diǎn)的參數(shù)格式為{x,y x,y}

<svg>
    <polygon v-bind:points="points"></polygon>
    <circle cx="100" cy="100" r="90"></circle>
</svg>

2、引用了一個(gè)新庫(kù),叫TweenLite.js,還有一個(gè)系列的動(dòng)畫(huà)庫(kù),簡(jiǎn)單好用
3、data返回了一個(gè)函數(shù),是為了不同實(shí)例不共享數(shù)據(jù)
4、sides監(jiān)控處出現(xiàn)一個(gè)想當(dāng)然的問(wèn)題,見(jiàn)代碼解釋
5、動(dòng)畫(huà)的循環(huán)是通過(guò)resetInterval中的定時(shí)器實(shí)現(xiàn)的,動(dòng)畫(huà)的漸變是監(jiān)控了stats的變化。

render函數(shù)

第一個(gè)例子
<div id="app-01">
  <anchored-heading :level="2">Hello world!</anchored-heading>
</div>
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:''
  }
})
完整例子
<div id="app-01">
  <anchored-heading :level="1">
  hello world
  </anchored-heading>
</div>
//創(chuàng)建一個(gè)查找并遞歸子文本的函數(shù)
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,'-')
//把開(kāi)頭結(jié)尾的‘-’替換為空
    .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()

  • 三部分組成:
    • 標(biāo)簽名,必須,此例中是'h'+this.level和'a'
    • data object參數(shù),不是必須的,{},即各種屬性設(shè)定,class/style/attrs/props/domProps/on/nativeOn/directives/scopedSlots/slot/key/ref(class和style級(jí)別最高)
    • 子節(jié)點(diǎn)或者內(nèi)容,必須,如果是子節(jié)點(diǎn),因?yàn)椴恢挂粋€(gè),所以需要加一個(gè)[]表示為數(shù)組形式,(但是每個(gè)子元素必須唯一)子節(jié)點(diǎn)就是嵌套的createElement(),如果是內(nèi)容,直接就是字符串,例子是,this.$slots.default。
  • render的形式
render:function(createElement){
                    一些預(yù)操作
               return createElement(組成內(nèi)容)
使用js來(lái)代替模板功能
  • v-if&v-for變?yōu)樵膇f/else&for(map)
<div id="app-01">
  <component-vif :items="items"></component-vif>
</div>
Vue.component('component-vif',{
  props:["items"],
//由于items使用了map和length,所以應(yīng)該為一個(gè)數(shù)組對(duì)象,且包含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要自己實(shí)現(xiàn)相應(yīng)邏輯
<div id="app-01">
  <component-vmodel :orivalue="value"></component-vmodel>
</div>
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:''
  }
})

注意問(wèn)題

<div id="app-01">
<com-keymod >
<com-keymod></com-keymod>
</com-keymod>
</div>
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
  - 靜態(tài)內(nèi)容:this.$slots.default

template:'<div><slot name="foo"></slot></div>'
相當(dāng)于:
render:function(createElement){
return createElement('div',this.$slots.foo)
}

  - 作用域slot,子組件

template:'<div><slot :text="msg"></slot></div>'
相當(dāng)于:
render:function(createElement){
return createElement('div',[
this.$scopedSlots.default({
text:this.msg
})])
}

  - 作用域slot,父組件

template:'<child><template scope="props"><span>{{props.text}}</span></template></child>'
相當(dāng)于:
render:function(createElement){
return createElement('child',{
scopedSlots:{
default:function(props){
return createElement('span',props.text)
}
}
})
}


學(xué)到此處,我默默回頭復(fù)習(xí)了一下組件內(nèi)slot部分
- JSX
為了把render內(nèi)的語(yǔ)句寫(xiě)的更接近模板一點(diǎn),可以用JSX語(yǔ)法,安裝babel的插件實(shí)現(xiàn)
- 函數(shù)化組件
(存疑)例子有問(wèn)題
- 模板編譯:vue的模板實(shí)際是編譯成了render函數(shù)

####自定義指令
- 第一個(gè)簡(jiǎn)單例子,同樣需要補(bǔ)充完整:

<input id="app-01" v-focus>111
Vue.directive('focus',{
inserted:function(el){
el.focus()
}
})
var app01=new Vue({
el:'#app-01',
//寫(xiě)在實(shí)例作用域內(nèi)
/*
directives:{
focus:{
inserted:function(el){
el.focus()
}
}
}
*/
})

類似于組件的寫(xiě)法,兩種寫(xiě)法,一種是全局自定義指令,另一種是定義在實(shí)例作用域內(nèi)部
- 鉤子函數(shù)和函數(shù)參數(shù)

<div id="app-02" v-demo:hello.a.b="message"></div>
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(',')
}
}
}
})

鉤子函數(shù)有:
  - bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用
  - inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用)
  - update:被綁定元素所在的模板更新時(shí)調(diào)用,而不論綁定值是否變化。
  - componentUpdated:被綁定元素所在模板完成一次更新周期時(shí)調(diào)用
  - unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用

  鉤子函數(shù)參數(shù)有:
  - el:指令所綁定的元素
  - binding:一個(gè)對(duì)象,包含以下屬性:
     - name:指令名(不含v-前綴)
     - value:指令的綁定值(計(jì)算后的)
     - expression:綁定值的字符串形式
     - oldValue:指令綁定的前一個(gè)值
     - arg:傳給指令的參數(shù)
     - modifiers:一個(gè)包含修飾符的對(duì)象
  - vnode:Vue編譯生成的虛擬節(jié)點(diǎn)
  - oldValue:上一個(gè)虛擬節(jié)點(diǎn)
- 函數(shù)簡(jiǎn)寫(xiě):
如果只想用bind和update鉤子,可以省略鉤子名稱這一步,直接寫(xiě):

//這是實(shí)例內(nèi)directives內(nèi)
swatch:function(el,binding,vnode){
el.style.backgroundColor=binding.value
}

- 對(duì)象字面量
之前的例子都是傳入對(duì)象名稱,比如:

<div id="app-02" v-swatch="color">111</div>
var app02=new Vue({
el:'#app-02',
data:{
message:"hello",
color:'#123456'
},
directives:{
swatch:function(el,binding,v){
el.style.backgroundColor=binding.value
}
}
})

也可以直接傳入一個(gè)js對(duì)象字面量,比如:

<div id="app-02" v-swatch="{color:'#125678'}">111</div>
var app02=new Vue({
el:'#app-02',
data:{
message:"hello"
},
directives:{
swatch:function(el,binding,v){
//注意這里,因?yàn)閭魅氲氖且粋€(gè)對(duì)象,因此需要在value后面加上對(duì)象屬性,才能索引到對(duì)應(yīng)的值
el.style.backgroundColor=binding.value.color
}
}
})


####混合
- 第一個(gè)簡(jiǎn)單例子:

//定義一個(gè)混合對(duì)象
var myMixin = {
created:function(){
this.hello()
},
methods:{
hello:function(){
console.log('hello from mixin!')
}
}
}
var Component = Vue.extend({
mixins:[myMixin]
})
var component=new Component()

>這個(gè)例子中出現(xiàn)了不熟悉的語(yǔ)句,于是我決定去復(fù)習(xí)一下組件的創(chuàng)建和注冊(cè)
- 首先,平常的組件創(chuàng)建,都是直接注冊(cè)的,使用的以下形式

Vue.component("name","arg")

這其實(shí)是把兩個(gè)步驟合為一個(gè)步驟
  - 步驟一,創(chuàng)建組件構(gòu)造器

//這是Vue構(gòu)造器的擴(kuò)展,創(chuàng)建了一個(gè)組件構(gòu)造器
var a=Vue.extend(各種參數(shù),比如template)

  - 步驟二,注冊(cè)組件

Vue.component("name","組件構(gòu)造器(a)")

所以平時(shí)輸入的arg其實(shí)就是一個(gè)組件構(gòu)造器,在需要復(fù)用組件的組成的時(shí)候,就可以把a(bǔ)rg拆出來(lái)復(fù)用一下

- 創(chuàng)建——注冊(cè)——掛載,組件使用的三步驟:
  - 最常見(jiàn):創(chuàng)建和注冊(cè)同時(shí)完成,掛載利用其它vue實(shí)例,在其內(nèi)部使用

<div id="app-01"><mycom></mycom></div>
//創(chuàng)建+注冊(cè)
Vue.component("mycom",{
我是組件構(gòu)造器的內(nèi)容
})
//利用其它vue實(shí)例實(shí)現(xiàn)掛載
var app01=new Vue({
el:'#app-01'
})

  - 不注冊(cè)也存在:不注冊(cè)組件,只創(chuàng)建,通過(guò)實(shí)例化,后臺(tái)可以看到console語(yǔ)句

mycom=Vue.extend({
我是組件構(gòu)造器的內(nèi)容
})
new mycom()


 >回到開(kāi)始的例子,首先定義了一個(gè)混合對(duì)象myMixinm,然后定義了一個(gè)組件構(gòu)造器,命名為Component,然后用這個(gè)構(gòu)造器創(chuàng)建了一個(gè)實(shí)例,由于沒(méi)有掛載,也沒(méi)注冊(cè)組件,所以只能后臺(tái)看到它確實(shí)存在
- 選項(xiàng)合并和優(yōu)先性:
 - 同名鉤子函數(shù)將被合并為一個(gè)數(shù)組,混合對(duì)象的鉤子優(yōu)先調(diào)用

var myMixin = {
template:'<p>2222</p>',
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

  - 值為對(duì)象的選項(xiàng),將被合并為同一個(gè)對(duì)象,鍵名沖突時(shí),取組件對(duì)象的鍵值對(duì):

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!

- 全局注冊(cè)混合對(duì)象:會(huì)影響所有之后創(chuàng)建的Vue實(shí)例,慎用:

Vue.mixin({
template:'<p>222</p>',
created:function(){
var myOption=this.$options.myOption
if(myOption){
console.log(myOption)
}
}
})
var app01=new Vue({
el:'#app-01',
myOption:'hello!'
})
//頁(yè)面:222
//后臺(tái):hello!

- 自定義選項(xiàng)的混合策略:默認(rèn)是覆蓋已有值

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

修改的方式?jīng)]測(cè)試出來(lái)(存疑)

####插件
 - vue-element
 - vue-touch
 - vuex
 - vue-router
社區(qū):[awesome-vue](https://github.com/vuejs/awesome-vue#libraries--plugins)
***
接下來(lái)的內(nèi)容需要結(jié)合webpack和vue的插件,進(jìn)階部分到此結(jié)束啦

11111111111
1111111111111111111
111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111
1111111111111111
1111111111111111
111111111111111111
111111111111111111
111111111111111
11111111111111111
111111111111111111
11111111111111111
111111111111111111
11111111111111111
11111111111111111
11111111111
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,079評(píng)論 0 29
  • 下載安裝搭建環(huán)境 可以選npm安裝,或者簡(jiǎn)單下載一個(gè)開(kāi)發(fā)版的vue.js文件 瀏覽器打開(kāi)加載有vue的文檔時(shí),控制...
    冥冥2017閱讀 6,081評(píng)論 0 42
  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,241評(píng)論 0 6
  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象,但只有一個(gè)實(shí)例,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見(jiàn)的單例模式,...
    Obeing閱讀 2,097評(píng)論 1 10
  • 1.安裝 可以簡(jiǎn)單地在頁(yè)面引入Vue.js作為獨(dú)立版本,Vue即被注冊(cè)為全局變量,可以在頁(yè)面使用了。 如果希望搭建...
    Awey閱讀 11,096評(píng)論 4 129