说说axios和mvc

首先Vue里面用到了mvc,那么要理解Vue就要先从mvc讲起
接下来我们通过写一个图书信息展示来理解
html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <div id="app">
    <div>
      书名:"JavaScript高级程序设计"
      数量:<span id="number">2</span>
    </div>
    <button id="add">加一</button>
    <button id="minus">减一</button>
    <button id="reset">归零</button>
  </div>
</body>
</html>

js

$("#app").on("click","#add",function(){
  var oldNumber=$("#number").text()
  var newNumber = oldNumber-0+1
  $("#number").text(newNumber)
})

$("#app").on("click","#minus",function(){
  var oldNumber=$("#number").text()
  var newNumber = oldNumber-0-1
  $("#number").text(newNumber)
})

$("#app").on("click","#reset",function(){
  var newNumber = 0
  $("#number").text(newNumber)
})

上面的代码是直接把数据写进页面里的,我们可以发一个请求来得到这个数据再写到页面里,这里我们引入axios来请求数据,并在真正返回response之前用axios的拦截机拦截一下,然后修改response之后再返回response

axios.interceptors.response.use(function(response){
    let {url,method,data}=response.config
    if(url === '/books/1' && method === 'get'){
      response.data = {
        name:'JavaScript高级程序设计',
        number:2,
        id:1
      }
    }
  return response
})

axios.get('/books/1').then((response)=>{
  let{data} = response
  let originalHtml = $('#app').html()
  let newHtml = originalHtml.replace('__name__',data.name)
  .replace('__number__',data.number)
  $('#app').html(newHtml)
})

这里先用axios发一个get请求,然后拦截机里的response.config可以拿到请求的url,method,data,如果请求的url是“/books/1”而且方法是get那么就返回数据,同时原始html里的number,name用__name____number__代替。当请求成功拿到response之后,拿到里面的data,然后把data里面的name和number的值替换之前的__name____number__
然后每次点击按钮,能不能也发一个put请求,然后通过响应再改数值,还是用axios来put请求

$("#app").on("click","#add",function(){
  var oldNumber=$("#number").text()
  var newNumber = oldNumber-0+1
  axios.put('/books/1',{number:newNumber}).then(()=>{
     $("#number").text(newNumber)
  })
})
var book={
  name:'JavaScript高级程序设计',
  number:2,
  id:1
}
axios.interceptors.response.use(function(response){
    let {url,method,data}=response.config
    if(url === '/books/1' && method === 'get'){
      response.data = book
    }else if(url === '/books/1' && method === 'put'){
      data = JSON.parse(data)
      Object.assign(book,data)
      console.log(book)
      response.data = book
    }
  return response
})

把newNumber当做data一起请求过去,然后为这个put做一个路由,当url和method都满足后,先把请求的data变成对象,然后用Object.assign这个api把book里面的number替换掉,再返回这个book。
到这里我们已经完成了一个人“意大利面条式代码”,长短交错看起来很乱,而且数据视图还有逻辑都是想到哪里写哪里,这就有了引入mvc的需求。
“m”就是“model”负责数据,
“v”就是view负责页面样式,
“c”就是controller负责逻辑,

let model={
  data:{
    name:'',
    number:0,
    id:''
  },
  fetch(id){
    return axios.get(`/books/${id}`).then((response)=>{
      this.data = response.data
      return response
    })
  },
  updata(data){
    let id = this.data.id
    return axios.put(`/books/${id}`,data).then((response)=>{
      this.data = response.data
      return response
    })
  }
}

model首先有一个data初始值,然后fetch函数发一个get请求,然后取到响应的data再把它赋值给model的data,updata函数也是一样的。

let view = {
  el:'#app',
  template:`
    <div>
      书名:《__name__》
      数量:<span id="number">__number__</span>
    </div>
    <button id="add">加一</button>
    <button id="minus">减一</button>
    <button id="reset">归零</button>
  `,
  render(data){
    let html = this.template.replace('__name__',data.name)
    .replace("__number__",data.number)
    $(this.el).html(html)
  }
}

view里面有操作的元素el:'#app',然后是HTML模板,render函数接受一个data然后用data里面的name和number来替代模板HTML里的对应元素,再把新的HTML渲染到el里面

let controller = {
  init(options){              //init接受一个对象{view:view,model:model}
    let view = options.view
    let model = options.model
    this.view = view                      //把view和model绑到controller上面
    this.model = model
    this.view.render(this.model.data)    //页面做一个初始化,把model里面data的初始值渲染到页面
    this.bindEvents()                  //绑定事件
    this.model.fetch(1).then(()=>{
      this.view.render(this.model.data)   
    })                  //拿到拦截机返回的response然后赋值到model的data上,render函数渲染拿到的data到页面
  },
  addOne(){   
    var oldNumber=$("#number").text()
    var newNumber = oldNumber-0+1
    this.model.updata({number:newNumber})   //这里的this是addOne,后面bind(this)之后才是controller
      .then(()=>{
      this.view.render(this.model.data)
    })
  },
  minus(){   
    var oldNumber=$("#number").text()
    var newNumber = oldNumber-0-1
    this.model.updata({number:newNumber})
      .then(()=>{
      this.view.render(this.model.data)
    })
  },
  reset(){
    var newNumber = 0
    this.model.updata({number:0})
      .then(()=>{
      this.view.render(this.model.data)
    })
  },
  bindEvents(){
    $(this.view.el).on("click",'#add',this.addOne.bind(this))  //第一个this是controller,bind(this)让addOne里面的this和外面的一样都是controller
    $(this.view.el).on("click","#minus",this.minus.bind(this))
    $(this.view.el).on("click","#reset",this.reset.bind(this))
  }
}

这样mvc三部分就写完了!
那么为了避免每一个页面都要重新写一遍这三个模型,于是想到可以写一个构造函数,然后每次就只用new就可以了
思路是把私有的属性放到构造函数里,调用的时候传进去,把公用属性放到原型里

function Model(options){
  this.data = options.data
  this.resource = options.resource
}
Model.prototype.fetch = function(id){
  return axios.get(`/${this.resource}s/${id}`).then((response) => {
      this.data = response.data
      console.log(this.data)
      return response
    })
}
Model.prototype.update = function(data){
  let id = this.data.id 
    return axios.put(`/${this.resource}s/${id}`, data).then((response) => {
      this.data = response.data 
      console.log('response')
      console.log(response)
      return response
    })
}
let model = new Model({
  data: {
    name: '',
    number: 0,
    id: ''
  },
  resource: 'book'
})
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>
    书名:《__name__》
    数量:<span id=number>__number__</span>
    </div>
    <div>
      <button id="addOne">加1</button>
      <button id="minusOne">减1</button>
      <button id="reset">归零</button>
    </div>
  `
})

接下来引入Vue,Vue强制把data传给view,因为Vue需要用data来初始化
template,不需要render。Vue会把当前model的data里的所有属性更新到View上面,所以直接修改View的值view.book = model.data这样直接替换了之前的render函数,只需要更新view里的data,就会自动更新HTML。

let view =new Vue({
  el:'#app',
  data:{
    book:{   
      name:'未命名',
      number:0,
      id:"" 
    },
    n:1
  },
  template:`
    <div>
    <div>
      书名:《{{book.name}}》
      数量:<span id="number">{{book.number}}</span>
    </div>
    <div>
       <input v-model="n" />      
      N 的值是 {{n}}
    </div>
    <div>
        <button v-on:click='addOne'>加N</button>   //绑定事件
        <button v-on:click='minus'>减N</button>
        <button v-on:click='reset'>归零</button>
    </div>
    </div>
  `,
  created(){
    model.fetch(1).then(()=>{
      this.book = model.data
    })
  },
  methods:{
    addOne(){   
      model.updata({
        number:this.book.number+(this.n-0)
      })
        .then(()=>{
          view.book = model.data
      })
    },
    minus(){   
      model.updata({
        number:this.book.number-(this.n-0)
      })
        .then(()=>{
          view.book = model.data
      })
    },
    reset(){
      model.updata({
        number:0
      })
        .then(()=>{
          view.book = model.data
      })
    }
  }
})

可以使用v-model指令在<input>元素上进行双向数据绑定。
双向数据绑定:之前我们可以通过book.number=3来修改内存值,然后Vue根据修改的内存值去更新<span>里的数字,只就是单向绑定。如果我们引入<input>标签,当我们修改<span>标签里的数字,这时Vue会根据修改的数据来修改内存值,这就是双向绑定。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容

  • 关于axios是一个ajax的库 以前用ajax是这么用的 可以用axios.ajax()也可以用axios.po...
    tsl1127阅读 209评论 0 1
  • 前言:看本文之前需要了解最基本的MVC思想(附一篇本人之前写的MVC设计模式在JavaScript中的运用 仅供参...
    EnochQin阅读 4,559评论 0 6
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,050评论 0 29
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,100评论 1 32
  • 响应式布局的理解 响应式开发目的是一套代码可以在多种终端运行,适应不同屏幕的大小,其原理是运用媒体查询,在不同屏幕...
    懒猫_6500阅读 785评论 0 0