從 jQuery 到 VUE 技術棧

當前前端最火熱的框架當屬 VUE,在學習 VUE 以前先來看下 VUE 的內部是如何工做的。html

咱們從最基本的頁面操做開始作起。前端

用 jQuery 操做頁面

咱們來實現一個頁面,當點擊按鈕式,頁面上的數字增長或減小ios

<div class="app">
  <div class="book">
    書籍:《JavaScript高級程序設計》
    數量:<span class='number'>2</span>
  </div>
  <button class='addOne'>加1</button>
  <button class='minusOne'>減1</button>
  <button class='reset'>清零</button>
</div>

用 jQuery 操做它很容易實現需求ajax

let log = console.log.bind(console)     //把console.log 替換成 log 少打點代碼
$('.addOne').on('click',()=>{
  let oldHtml = $('.number').text()
  let newHtml = oldHtml -0 +1
  $('.number').html(newHtml)
})
$('.minusOne').on('click',()=>{
  let oldHtml = $('.number').text()
  let newHtml = oldHtml -0 -1
  $('.number').html(newHtml)
})
$('.reset').on('click',()=>{
  $('.number').text('0')
})

axios 實現 ajax

咱們真實的需求是,當點擊按鈕時,操做的時數據庫裏的數據,而不是直接在頁面中操做。數據庫

這裏引入一個庫axios,能夠實如今前端模擬後臺,它有一個重要的 API:interceptors,能夠實如今它上面 Mock 數據axios

// 咱們要的數據
let book = {
  name:'JavaScript高級程序設計',
  number:2,
  id:''
}
axios.interceptors.response.use((response)=>{
  //下面這句等價於 let {url,method,data} = response.config
  let {config:{url,method,data}} = response        // 這裏的 data 是請求體
  if(url === '/book/1' && method === 'get'){
     response.data = book    //這裏的 data 是響應體
  }else if(url === '/book/1' && method === 'put'){
    data = JSON.parse(data)
    Object.assign(book,data)     //請求體 data,assign可實現局部更新
    response.data = book        //響應體 data
  }
  return response
})

頁面中的數據咱們應該用佔位符代替,數據獲取到以後 更新到頁面中服務器

//剛進入頁面後的數據加載
axios.get('/book/1').then(({data})=>{
  let oldHtml = $('.app').html()
  let newHtml = oldHtml.replace('__name__',data.name) 
    .replace('__number__',data.number)    //用真實數據替換佔位符
  $('.app').html(newHtml)
})
$('.app').on('click','.addOne',()=>{
  let oldNumber = $('.number').text()
  let newNumber = oldNumber -0 +1
  axios.put('/book/1',{number:newNumber}).then(({data})=>{    //請求時更新最新數據
    $('.number').html(data.number)
  })
})
$('.app').on('click','.minusOne',()=>{
  let oldNumber = $('.number').text()
  let newNumber = oldNumber -0 -1
  axios.put('/book/1',{number:newNumber}).then(({data})=>{
    $('.number').html(data.number)
  })
})
$('.app').on('click','.reset',()=>{
  axios.put('/book/1',{number:0}).then(({data})=>{
    $('.number').html(data.number)
  })
})

這樣的意大利麪條似的寫法,很是不利於後期維護,咱們應該用 MVC 優化下app

用 MVC 優化

獲取數據,更新數據的事情交個model去作,model裏面有三個屬性:datafetchupdata;分別用來:data負責存儲最新數據,fetch負責頁面加載時向服務器獲取數據,並將數據存儲到data中,updata負責實時頁面操做時,更新頁面數據,並將最新數據保存到data中。框架

let model ={
  data:{    //model 內部用來存儲數據
    name:'',
    number:0,
    id:''
  },
  fetch(id){
    return axios.get(`/books/${id}`).then((response)=>{
      this.data = response.data        //加載更新向 axios 獲取的數據
      return response      
    })
  },
  updata(id,data){
    return axios.put(`/books/${id}`,data).then((response)=>{
      this.data = response.data        //點擊按鈕向 axios 獲取最新數據,請求中的 data 是最新數據
      return response
    })
  }
}

操做頁面交給viewview有三個屬性,分別是eltemplaterenderel負責視圖部分,也就是你須要操做的 DOM,template是虛擬的html,並經過render去渲染。函數

let view = {
  el:'.app',
  template:`
    <div>
      <div class="book">
        書籍:《__name__》
        數量:<span class='number'>__number__</span>
      </div>
      <button class='addOne'>加1</button>
      <button class='minusOne'>減1</button>
      <button class='reset'>清零</button>
    </div>`,
  render(data){
    let newHtml = this.template.replace('__name__',data.name)    
      .replace('__number__',data.number)    //把佔位符替換成數據
    $(this.el).html(newHtml)
  }
}

事件相關的交給controller操做,有兩個重要的屬性:initbingEvents;初始化時須要傳入兩參數viewmodel,後面操做的都是在的viewmodel都是在controller身上,而不是直接操做model

let controller = {
  init({view,model}){
    this.view = view
    this.model = model
    this.bindEvents()
    this.model.fetch(1).then(()=>{  
      view.render(this.model.data)
    })
  },
  bindEvents(){
    $(this.view.el).on('click','.addOne',this.addOne.bind(this)) //這裏 addOne 內部的 this 應該是點擊的那個元素,因此這裏要綁一下 this
    $(this.view.el).on('click','.minusOne',this.minusOne.bind(this))
    $(this.view.el).on('click','.reset',this.reset.bind(this))
  },
  addOne(){
    console.log(1)
    let oldNumber = $('.number').text()
    console.log(2)
    let newNumber = oldNumber -0 +1
    console.log(3)
    this.model.updata(1,{number:newNumber}).then(()=>{
        $('.number').html(this.model.data.number)
    })
    console.log(4)
  },
  minusOne(){
    let oldNumber = $('.number').text()
    let newNumber = oldNumber -0 -1
    this.model.updata(1,{number:newNumber}).then(()=>{
      $('.number').html(this.model.data.number)
    })
  },
  reset(){
    this.model.updata(1,{number:0}).then(()=>{
      $('.number').html(this.model.data.number)
    })
  }    
}
controller.init({view:view,model:model})

優化 MVC

如今是一個頁面,這也寫沒有關係,但若是有不少頁面,每一個頁面中的viewmodelcontroller都重複了,這裏把一些公用的方法寫在原型上。

在頁面中使用model,只須要傳遞兩參數

function Model({data,resouce}){
  this.data = data
  this.resouce = resouce
}

Model.prototype.updata = function(id,data){
  return axios.put(`/${this.resouce}s/${id}`,data).then((response)=>{
    this.data = response.data
    return response
  })
}

Model.prototype.fetch = function(id){
    return axios.get(`/${this.resouce}s/${id}`).then((response)=>{
      this.data = response.data
      return response      
    })
}
let model = new Model({
  data:{
    name:'',
    number:0,
    id:''
  },
  resouce:'book'  
})

view也是,頁面使用時,傳兩個參數就 ok 了

function View({el,template}){
  this.el = el
  this.template = template
}
View.prototype.render = function(data){ 
  let html = this.template    
  for(let key in data){    //遍歷傳進來的參數,用循環替換頁面中的佔位符
    html = html.replace(`__${key}__`,data[key])
  }
  $(this.el).html(html)
}
let view = new View({
  el:'.app',
  template:`
    <div>
      <div class="book">
        書籍:《__name__》
        數量:<span class='number'>__number__</span>
      </div>
      <button class='addOne'>加1</button>
      <button class='minusOne'>減1</button>
      <button class='reset'>清零</button>
    </div>`
})

Controller公用的方法比較少,這裏就沒有優化了

VUE

理解了 MVC 以後再來看 VUE 就會很簡單,VUE 簡單來講就是 MVC 中的 V,但它和 MVC 有點區別,就是它須要model中的數據

let view = new Vue({
  el:'.app',
  data:{
    book:{
       name:'我是書籍',
       number:0,
       id:'' 
     },
    n:1
  },
  template:`
    <div>
      <div class="book">
        書籍:《{{book.name}}》
        數量:<span class='number'>{{book.number}}</span>
      </div>
      <button class='addOne'>加1</button>
      <button class='minusOne'>減1</button>
      <button class='reset'>清零</button>
    </div>`
  }

VUE 會把data裏的屬性提高爲 Vue 的屬性,因此下面操做能夠直接用Vue.name操做,而不是寫Vue.data.name,因此咱們能夠在這些屬性外面套一層book,用Vue.book就能夠對這些屬性進行批量操做。

Vue沒有render方法,那你會說它怎麼實現渲染頁面呢?

它提供了一個叫created的方法,在裏面直接修改Vuedata屬性,它就會自動幫你渲染頁面

created(){
    model.fetch(1).then(()=>{
      this.book = model.data
    })

固然 VUE 的野心不止於此 ,它甚至幫你省下controllor,你都不須要進行事件綁定

<button class='addOne' v-on:click="addOne">加1</button>
<button class='minusOne' v-on:click="minusOne">減1</button>
<button class='reset' v-on:click="reset">清零</button>

它在templatev-on:click的一個方法,它會幫你調用methods中的方法,你只須要將點擊執行的函數寫在上面便可。

methods:{
    addOne(){
      model.updata(1,{number:this.book.number + (this.n-0)})
        .then(()=>{
          this.book = model.data
        })
    },
    minusOne(){
      model.updata(1,{number:this.book.number - (this.n-0)})
        .then(()=>{
          this.book = model.data
        })
    },
    reset(){
      model.updata(1,{number:0})
        .then(()=>{
          this.book = model.data
        })
    }
}

學會了 MVC 以後在來看 VUE,就變的很簡單

MVVM

VUE 還實現另外一個雙向綁定的功能,我如今點擊按鈕只能+1-1,若是我要實現操做+n或減n呢?

這裏用input實現,在按鈕上面添加一行

<div>
    <input v-model='n'>N的值是<span>{{n}}</span>
</div>

固然Vuedata中也要添加一個n

當你在input中輸入相應值時,後面N的值會相應變化,這就是 MVVM。

相關文章
相關標籤/搜索