axios
功能类似于jQuery.ajax
。
axios.post()
axios.get()
axios.put()
axios.patch()
axios.delete()
- 比
jQuery.ajax
功能更多 - 除了ajax功能之外没有其他功能(更庄专注)
ajax操作使用axios,dom操作使用vue,从此可以不使用jquery
Mock
使用axios模拟后台请求与响应就是Mock,也有专门的Moc库例如:
http://mockjs.com/
生成随机数据,拦截 Ajax 请求
使用axios和jQuery完成简单的前后台交互(请求与响应)
要求从后台获取数据,初始化书的数量。加减书的时候也发送请求与响应,同时更新后台数据。
演示地址:
https://jsbin.com/jipewutagi/...
<!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的点击事件,如果点的是委托的子元素,就执行监听的函数
上面的代码很乱。
使用 MVC模式 改写上面的代码
上面的代码很乱。使用MVC模式重构代码,把代码分成视图,数据,控制数据和视图三块,分别用一个对象表示,下面是过程
添加model,分离控制数据的方法
演示代码
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;
})
}
添加View,所有跟html相关的操作都给view来做
演示地址
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;
})
}
代码开始变得条理清晰
添加Controller (操纵Model和View)
把操纵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抽象成类
因为这个页面的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。
使用vue改写上面的代码
从上面的代码来看,view类的作用是:
- 有一个没有填充数据的HTML模板template
- model发送请求获取数据后,view把数据填充到模板里,然后渲染填充后的html到页面
VUE框架的作用是可以把MVC里的view类使用VUE代替。
注意:
- 需要直接传入data,传入data后vue对象就有了这个data的属性
- VUE会有自动的render机制,VUE会帮我们做渲染html的过程,那我们怎么更新(渲染)HTML呢?直接改data数据就好了双向绑定()
- template只能有一个根元素
从传统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
双向绑定
- 单向绑定:从内存里数据的更新到渲染页面的更新
- 双向绑定:不单单是从内存到页面,页面上的input修改了,还会反过来映射内存,内存会同时修改(只能input实现,因为只有input可以更改内存)
渲染是一种单向绑定,只单向得改变html的值。
vue就是自动化的mvc,既MVVM
MVVM
通过以上的分析,我们发现,我们不需要去绑定事件,也不需要去render了,我需要做的就是取值和赋值。
什么是MVVM:
https://juejin.im/entry/59996...
用vue做三个小东西
Vue 浮层例子:http://jsbin.com/nabugot/1/ed...
Vue 轮播例子:https://jsbin.com/kerabibico/...
Vue tab切换例子:http://jsbin.com/hijawuv/1/ed...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。