功能相似于jQuery.ajax
。css
axios.post() axios.get() axios.put() axios.patch() axios.delete()
jQuery.ajax
功能更多ajax操做使用axios,dom操做使用vue,今后能够不使用jqueryhtml
使用axios模拟后台请求与响应就是Mock,也有专门的Moc库例如:
http://mockjs.com/前端
生成随机数据,拦截 Ajax 请求vue
要求从后台获取数据,初始化书的数量。加减书的时候也发送请求与响应,同时更新后台数据。jquery
演示地址:
https://jsbin.com/jipewutagi/...ios
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>使用axios和jQuery完成简单的先后台交互(请求与响应)</title> <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <div id='app'> <div> 书的名称:《__name__》 <br> 书的数量:<span id='number'>__number__</span> </div> <button id='addOne'>加一</button> <button id='minusOne'>减一</button> <button id='reset'>归零</button> </div> </body> </html>
let book = { name:'JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){//若是,就把初始book的数据响应过来 response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data)//先把拿到的请求转化为对象 Object.assign(book,dataObj) // Object.assign这个函数的做用是局部更新对象,把接收到的请求(book)里面的number局部更新 console.log(book) response.data = book ;//局部更新后,再次赋值给响应,在这里略过存储数据库,由于这只是假的后台 } return response; }) // -------------上面是假的后台----------------- // 先声明好变量(有时候变量不能固定,好比更新了html的代码后,这个变量就是旧的,就得从新取) let $app = $('#app') // let $number = $('#number') // let $addOne = $('#addOne') // let $minusOne = $('#minusOne') // let $reset = $("#reset") // 请求初始值 axios.get('/book/1') .then(({data})=>{//获取响应成功后更新html的代码 // 这里使用的是es6语法,其实是let data = response.data let originalHtml = $app.html() let newHtml = originalHtml.replace('__name__',data.name).replace('__number__', data.number) $app.html(newHtml) }) // 进行加一个的请求 $app.on('click', '#addOne', function(){//事件委托,点击app上的addone的时候,将点击事件委托给addone let newNumber = $('#number').text()-0+1 let book = { number:newNumber } axios.put('/book/1', book) .then(({data})=>{ $('#number').text(data.number)//接收到响应以后在更新前端代码 }) }) //下面减一和重置同理 $app.on('click', '#minusOne', function(){//事件委托,点击app上的addone的时候,将点击事件委托给addone let newNumber = $('#number').text()-0-1 let book = { number:newNumber } axios.put('/book/1', book) .then(({data})=>{ $('#number').text(data.number)//接收到响应以后在更新前端代码 }) }) $app.on('click', '#reset', function(){//事件委托,点击app上的addone的时候,将点击事件委托给addone let newNumber = 0 let book = { number:newNumber } axios.put('/book/1', book) .then(({data})=>{ $('#number').text(data.number)//接收到响应以后在更新前端代码 }) })
事件委托:点击父元素,若是同时点到了子元素就把事件委托给他。
经过事件委托,监听app的点击事件,若是点的是委托的子元素,就执行监听的函数程序员
上面的代码很乱。es6
上面的代码很乱。使用MVC模式重构代码,把代码分红视图,数据,控制数据和视图三块,分别用一个对象表示,下面是过程ajax
演示代码
https://jsbin.com/ceyukirube/...数据库
fakeData() // -------------上面是假的后台----------------- let model = { data:{ name:'', number:0, id:'' }, fetch:function (id){ return axios.get(`/book/${id}`).then((response)=>{ this.data = response.data return response }) }, update:function(id,data){ return axios.put(`/book/${id}`,data).then((response)=>{ this.data = response.data return response }) } } let $app = $('#app') model.fetch(1).then(({data})=>{//这里把操做数据的方法写在了model里 let originalHtml = $app.html() let newHtml = originalHtml.replace('__name__',data.name).replace('__number__', data.number) $app.html(newHtml) }) $app.on('click', '#addOne', function(){ let newNumber = $('#number').text()-0+1 let book = { number:newNumber } model.update(1,book).then(({data})=>{//这里把操做数据的方法写在了model里 $('#number').text(data.number) }) }) $app.on('click', '#minusOne', function(){ let newNumber = $('#number').text()-0-1 let book = { number:newNumber } model.update(1,book) .then(({data})=>{ $('#number').text(data.number) }) }) $app.on('click', '#reset', function(){ let newNumber = 0 let book = { number:newNumber } model.update(1,book) .then(({data})=>{ $('#number').text(data.number) }) }) function fakeData(){//假的后台 let book = { name:'JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){ response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data) Object.assign(book,dataObj) console.log(book) response.data = book ; } return response; }) }
演示地址
https://jsbin.com/fakegurono/...
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>使用axios和jQuery完成简单的先后台交互(请求与响应)</title> <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <div id='app'> </div> </body> </html>
fakeData() // -------------上面是假的后台----------------- let model = { data:{ name:'', number:0, id:'' }, fetch:function (id){ return axios.get(`/book/${id}`).then((response)=>{ this.data = response.data return response }) }, update:function(id,data){ return axios.put(`/book/${id}`,data).then((response)=>{ this.data = response.data return response }) } } let view = { el:'#app', template:`<div> 书的名称:《__name__》 <br> 书的数量:<span id='number'>__number__</span> </div> <button id='addOne'>加一</button> <button id='minusOne'>减一</button> <button id='reset'>归零</button> `, render(data){//渲染 let newhtml = this.template.replace('__name__',data.name).replace('__number__', data.number) $(this.el).html(newhtml) } } let $app = $('#app') model.fetch(1).then(({data})=>{//es6语法,response里的data //这里把操做数据的方法写在了model里 view.render(data) // 或者view.render(model.data)由于上面model在操纵数据的时候,获取响应的时候,把data传给了model.data,因此response.data 和model.data同样,两个均可以用 }) $app.on('click', '#addOne', function(){ let newNumber = $('#number').text()-0+1 let book = { number:newNumber } model.update(1,book). then(({data})=>{//这里把操做数据的方法写在了model里 view.render(data) }) }) $app.on('click', '#minusOne', function(){ let newNumber = $('#number').text()-0-1 let book = { number:newNumber } model.update(1,book) .then(({data})=>{ view.render(data) }) }) $app.on('click', '#reset', function(){ let newNumber = 0 let book = { number:newNumber } model.update(1,book) .then(({data})=>{ view.render(data) }) }) //假的后台,不要看 function fakeData(){//假的后台 let book = { name:'JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){ response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data) Object.assign(book,dataObj) console.log(book) response.data = book ; } return response; }) }
代码开始变得条理清晰
把操纵model和view的操做封装成controller 对象
演示地址:
https://jsbin.com/sezuquxuko/...
fakeData() // -------------上面是假的后台----------------- let model = { data:{ name:'', number:0, id:'' }, fetch:function (id){ return axios.get(`/book/${id}`).then((response)=>{ this.data = response.data return response }) }, update:function(id,data){ return axios.put(`/book/${id}`,data).then((response)=>{ this.data = response.data return response }) } } let view = { el:'#app', template:`<div> 书的名称:《__name__》 <br> 书的数量:<span id='number'>__number__</span> </div> <button id='addOne'>加一</button> <button id='minusOne'>减一</button> <button id='reset'>归零</button> `, render(data){//渲染 let newhtml = this.template.replace('__name__',data.name).replace('__number__', data.number) $(this.el).html(newhtml) } } let controller = { init:function(options){ this.view = options.view this.model = options.model this.view.render(this.model.data) this.bindEvents() this.model.fetch(1).then(({data})=>{ this.view.render(data) }) }, bindEvents:function(){ //到这一层,this还指的是controller这个对象,可是到点击事件那一层,addOne函数里,this表明点击的那个元素(jQuery规定的)。 // 因此要使用addOne.bind(this)把controller这一层的this绑定到addOne那更深刻的一层去,使this同一为controller这个对象 $(this.view.el).on('click', '#addOne', this.addOne.bind(this)) $(this.view.el).on('click', '#minusOne',this.minusOne.bind(this) ) $(this.view.el).on('click', '#reset', this.reset.bind(this)) }, addOne:function(){ let newNumber = $('#number').text()-0+1 let book = {number:newNumber} this.model.update(1,book).//这个this已经被bind为controller then(({data})=>{ this.view.render(data)//这个this已经被bind为controller }) }, minusOne:function(){ let newNumber = $('#number').text()-0-1 let book = { number:newNumber } this.model.update(1,book)//这个this已经被bind为controller .then(({data})=>{ this.view.render(data) }) }, reset:function(){ let newNumber = 0 let book = { number:newNumber } this.model.update(1,book) .then(({data})=>{ this.view.render(data) }) } } controller.init({model:model,view:view})//初始化,并把Model和View传进去 //假的后台,不要看 function fakeData(){//假的后台 let book = { name:'JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){ response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data) Object.assign(book,dataObj) console.log(book) response.data = book ; } return response; }) }
由于这个页面的Model和View只是这个页面特有的,假以下个页面不是这个View和Model,那么还须要从新重写一遍代码,因此要把把Model,View和controller抽象成类。这样每有新的页面中的一块html须要操做,就new一个对象便可。通常来讲MVC作成一个库,而后去引用他就行了
先写构造函数,而后把公有属性写在prototype里,最后new就能够了。
演示地址:
https://jsbin.com/mifameqona/...
controller类暂时不写
fakeData() // -------------上面是假的后台----------------- //从这开始写MVC类 function Model(options){//这里面写特有的属性 this.data = options.data this.resource = options.resource//把请求的地址也写成特有的属性 } Model.prototype.fetch = function(id){//共有属性 return axios.get(`/${this.resource}/${id}`).then((response)=>{ this.data = response.data return response }) } Model.prototype.update = function(id,data){ return axios.put(`/${this.resource}/${id}`,data).then((response)=>{ this.data = response.data return response }) } function View(options){ this.el = options.el; this.template = options.template; } View.prototype.render = function(data){ var newhtml = this.template for(let key in data){ newhtml = newhtml.replace(`__${key}__`,data[key])//用循环替换data里面的字符串 } $(this.el).html(newhtml) } // --------上面是MVC类----------- //使用MVC类新生成的对象 let bookModel = new Model({data:{name:'',number:0,id:''},resource:'book'}) let bookView = new View({ el:'#app', template:`<div> 书的名称:《__name__》 <br> 书的数量:<span id='number'>__number__</span> </div> <button id='addOne'>加一</button> <button id='minusOne'>减一</button> <button id='reset'>归零</button> ` }) let controller = { init:function(options){ this.view = options.view this.model = options.model this.view.render(this.model.data) this.bindEvents() this.model.fetch(1).then(({data})=>{ this.view.render(data) }) }, bindEvents:function(){ //到这一层,this还指的是controller这个对象,可是到点击事件那一层,addOne函数里,this表明点击的那个元素(jQuery规定的)。 // 因此要使用addOne.bind(this)把controller这一层的this绑定到addOne那更深刻的一层去,使this同一为controller这个对象 $(this.view.el).on('click', '#addOne', this.addOne.bind(this)) $(this.view.el).on('click', '#minusOne',this.minusOne.bind(this) ) $(this.view.el).on('click', '#reset', this.reset.bind(this)) }, addOne:function(){ let newNumber = $('#number').text()-0+1 let book = {number:newNumber} this.model.update(1,book).//这个this已经被bind为controller then(({data})=>{ this.view.render(data)//这个this已经被bind为controller }) }, minusOne:function(){ let newNumber = $('#number').text()-0-1 let book = { number:newNumber } this.model.update(1,book)//这个this已经被bind为controller .then(({data})=>{ this.view.render(data) }) }, reset:function(){ let newNumber = 0 let book = { number:newNumber } this.model.update(1,book) .then(({data})=>{ this.view.render(data) }) } } controller.init({model:bookModel,view:bookView})//初始化,并把Model和View传进去 //假的后台,不要看 function fakeData(){//假的后台 let book = { name:'JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){ response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data) Object.assign(book,dataObj) console.log(book) response.data = book ; } return response; }) }
在前端开始慢慢发展的时候,前端程序员就是这样进行技术迭代的,上面就是MVC迭代的过程。这就是MVVM出现以前的MVC。
从上面的代码来看,view类的做用是:
VUE框架的做用是能够把MVC里的view类使用VUE代替。
注意:
从传统MVC转到VUE的MVC就是忘掉render,把data放到vue上面,要更新数据,就直接更新vue里面的data便可。
把render变成了简单的赋值操做。并且这种渲染只更新你改变的那个值所在的节点,不会渲染所有模板。
vue第一个特色是data归他管,第二就是会精细得更新该渲染的地方。
但vue的野心不只于此,vue可让你作到不须要controller。由于controller最重要的功能绑定事件,vue有一种语法能够绑定事件。具体用法是在html属性里添加v-on:click="f",而后在methods 里写f函数便可。
代码
演示地址:
https://jsbin.com/bocecuxaya/...
主要代码:
fakeData() // -------------上面是假的后台----------------- //从这开始写MVC类 function Model(options){ this.data = options.data this.resource = options.resource } Model.prototype.fetch = function(id){ return axios.get(`/${this.resource}/${id}`).then((response)=>{ this.data = response.data return response }) } Model.prototype.update = function(id,data){ return axios.put(`/${this.resource}/${id}`,data).then((response)=>{ this.data = response.data return response }) } // --------上面是Model类----------- let bookModel = new Model({data:{name:'',number:0,id:''},resource:'book'}) let bookView = new Vue({//不用写view类了,直接用vue充当view类,须要传入data, el:'#app', data:{//data里的属性会转变为vue对象的属性 book:{ name:'', number:0, id:'1' }, n:1//两个数据,一个book对象,一个n的值 }, //template只能有一个根元素 template:` <div> <div> 书的名称:《{{book.name}}》 <br> 书的数量:<span id='number'>{{book.number}}</span> </div><br><br> 双向绑定:<br> 输入须要加或者减的数:<input type='text' v-model='n'><br> n的值为<span>{{n}}</span><br><br><br> <button v-on:click='addOne'>加n</button> <button v-on:click='minusOne'>减n</button> <button v-on:click='reset'>归零</button> </div> `, created:function(){//在创造vue时执行的函数,进行首次渲染 bookModel.fetch(1).then(({data})=>{ //vue会直接同步渲染html,因此直接赋值给view.name和number就行了 this.book = bookModel.data;//或者this.book = data;由于data是传回来的response,在model里,也把传回来的数据放到了model里 // this.view.render(this.model.data)这句不须要了,由于修改vue数据后会自动渲染 }) }, methods:{//绑定的事件的函数 addOne:function(){ let newNumber = this.book.number + (this.n-0)//+n //直接获取内存里的number,由于内存和页面是统一的,不须要获取dom了 let book = {number:newNumber} bookModel.update(1,book).//直接用声明的bookModel对象里面的update方法,由于没有controller了 then(({data})=>{ // this.view.render(data) this.book = data//返回的数据直接赋值给book,便可渲染 }) }, minusOne:function(){ let newNumber = this.book.number - (this.n-0)//-n let book = { number:newNumber } bookModel.update(1,book) .then(({data})=>{ // this.view.render(data) this.book = data }) }, reset:function(){ let newNumber = 0 let book = { number:newNumber } bookModel.update(1,book) .then(({data})=>{ // this.view.render(data) this.book = data }) } } }) //假的后台,不要看 function fakeData(){//假的后台 let book = { name:'我是初始名称JavaScriptBook', number:10, id:'1' } // 在response真正返回以前拦截,修改他的数据,使用这个api来模拟后台响应数据 axios.interceptors.response.use(function(response){ let {config: {url, method, data}} = response // ES6语法,从response里的config拿出url method data,并声明 if(url === '/book/1' && method === 'get'){ response.data = book } else if(url === '/book/1' && method === 'put'){ let dataObj = JSON.parse(data) Object.assign(book,dataObj) console.log(book) response.data = book ; } return response; }) }
可是vue无论model层的事
vue作的事就是让mvc里的v更智能,且能合并mvc的c
渲染是一种单向绑定,只单向得改变html的值。
vue就是自动化的mvc,既MVVM
经过以上的分析,咱们发现,咱们不须要去绑定事件,也不须要去render了,我须要作的就是取值和赋值。
什么是MVVM:
https://juejin.im/entry/59996...
Vue 浮层例子:http://jsbin.com/nabugot/1/ed...
Vue 轮播例子:https://jsbin.com/kerabibico/...
Vue tab切换例子:http://jsbin.com/hijawuv/1/ed...