1.几个面试题:
1.1. 简述MVVM:
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
1.2. 请简述Vue.js的优点
低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写
易用灵活高效
2. axios库的使用
axios是一个ajax的库
2.1. 与jq的ajax的区别
Jq
$.ajax({
url: ‘/xxx’,
method: ‘post’
})
$.post(‘/xxx’,data)
$.get(‘/xxx’)
axios
axios.post()
axios.get()
axios.put()
axios.patch()
axios.delete()
1. 比jquery.ajax功能更多
2. 除了ajax功能之外,就没有其它功能(更专注)
2.2. 使用axios自己造数据
//在真正返回response之前使用
axios.interceptors.response.use(function(response){
response.data = {
'name': 'frank'
}
return response
})
axios.get('/books/1')
.then((response)=>{
console.log(response)
})
这样代码运行就能打印出一个response对象,里面有一个data:{‘name’:’frank’}
![f3dfb637907ef3304784c3a15d614b91.png](https://i-blog.csdnimg.cn/blog_migrate/4e32bf8e7d39a855a417e03b0acef068.jpeg)
获取你请求的url和method
let config = response.config;
let {method, url, data} = config;
完整代码:
axios.interceptors.response.use(function(response){
let config = response.config
let {method, url, data} = config;//data是请求的data,也就是请求的第四部分
//上面两行等价于let {config: {method, url, data}} = response
if(url === '/books/1' && method === 'get'){
response.data = {//这个data是响应的data,也就是响应的第四部分
'name': 'frank'
}
}
return response
})
axios.get('/books/1')
.then((response)=>{
console.log(response)
})
上面的代码,当你请求的url是/books/1并且method是get的时候给response一个data对象
2.3. Object.assign():部分更新
assign就是赋值
![471eaa3935e6f40795dbea9e44bcdd37.png](https://i-blog.csdnimg.cn/blog_migrate/774bf269fd78a5bf4cbfb6103e8b6c10.jpeg)
还可以进行多次赋值
![0040b33f11bc3d2bf4907f8e0ced507d.png](https://i-blog.csdnimg.cn/blog_migrate/38cd039730ee451554f76f0db9461f55.jpeg)
如果有重复的赋值,后面的会把前面的覆盖掉
![859b763a7d6b32c8427d22a84fca42bf.png](https://i-blog.csdnimg.cn/blog_migrate/e6e4c524b1b0aed1f3cacfd45828083a.jpeg)
使用axios的一个小案例:
JS Binjsbin.com将上面的案例封装成mvc,完整代码:
JS Binjsbin.com![cc33286dc2aa1377ff05866e679f8fb9.png](https://i-blog.csdnimg.cn/blog_migrate/ef2451d1f43338bf940c13139eb9a90d.png)
上面的mvc你的页面里有三个对象,如果有第二个页面,你第二个页面也要写这三个对象,也就是你每个页面都要写三个对象,所以我们可以通过构造函数,把共有的代码全部写到它的原型上,独有的放在实例对象上
Model.prototype.fetch = function(id){
return axios.get(`/${this.resource}s/${id}`).then((response)=>{
this.data = response.data
return response //为了可以继续后面跟.then()
})
}
Model.prototype.updata = function(id, data){
return axios.put(`/${this.resource}s/${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){
let html = this.template
for(let key in data){
html = html.replace(`__${key}__`,data[key])
}
$(this.el).html(html)
}
//-------------上面是MVC类,下面是MVC对象
//这样你每次声明model就简化成两个属性了
let model = new Model({
//这个data是特有的,因为这个页面获取的是一本书,另一个页面获取的有可能是一辆车
data: {
name: '',
number: '',
id: ''
},
resource: 'book'
})
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>
`
})
完整代码:
JS Binjsbin.com![cc33286dc2aa1377ff05866e679f8fb9.png](https://i-blog.csdnimg.cn/blog_migrate/ef2451d1f43338bf940c13139eb9a90d.png)
3. 引入VUE
1.只需要把上面封装的构造函数的View删掉,然后把实例对象里面的new View改为new Vue
2.将__name__改成{{name}}
3.vue实例本身必须有一个data
let view = new Vue({
el: '#app',
data: {
name: '未命名',
number: 0,
id: ''
}
}
4.template必须只有一个根元素,如果有多个,那么就只显示第一个,解决办法在外面套一个div
![ab502824c54bd01b2ae8358556557dbc.png](https://i-blog.csdnimg.cn/blog_migrate/e0fa36170cf817c47a027972cac93603.jpeg)
上面代码因为template里面有两个根元素,所以只显示一个,后面的button都没显示,在外面套入一个div,就显示了
![e991d0047beeb700cfc6de459354bca3.png](https://i-blog.csdnimg.cn/blog_migrate/39720b3c46a0584071b8a3cd97735180.jpeg)
5.vue没有render方法,你要修改值的话,就通过变量修改就可以了
![a63b49a3b52613d75febc70920a46b7b.png](https://i-blog.csdnimg.cn/blog_migrate/9777d67e2d898b4faff45a4f1384f0ea.jpeg)
原本上面应该等价于
![cc6bdd2333754826f8ea6435a1583967.png](https://i-blog.csdnimg.cn/blog_migrate/88f12a7466f6b4b7b60d968bbdcfc0cd.jpeg)
但是vue中会把当前data的所有属性升级到当前的实例对象view上面,也就是说你不能直接去改data,你要改它的实例对象view,也就是下面的代码
![efd5914020b0d923f5612dbdc7676e89.png](https://i-blog.csdnimg.cn/blog_migrate/8f36ef9d4905f2d51f2d66e0e65071ee.png)
对上面代码进行改进,上面要同时对name和number进行更改,所以下面本来有render的地方都有换成这两句,比较麻烦,我们可以将name、number和id写如data里面的一个book对象里,然后每次对这个对象重新赋值就行
let view = new Vue({
el: '#app',
data: {
book: {
name: '未命名',
number: 0,
id: ''
}
}
}
let controller = {
init: function(view, model){
this.view = view;
this.model = model;
this.model.fetch(1)
.then(()=>{this.view.book = this.model.data})
this.bindEvent()
}
}
上面代码你在data里面写book属性,vue会认为是实例对象的book属性,而不是data的book属性
6.vue可以不需要controller
将controller里面除了绑定事件和初始化以外的代码全部写到vue里面的methods里,而初始化的代码就写在created方法里,然后绑定事件直接在元素上用v-on:click=”函数名”来绑定就行,代码如下:
let view = new Vue({
el: '#app',
data: {
book: {
name: '未命名',
number: 0,
id: ''
}
},
template: `
<div>
<div>
书名:《{{book.name}}》
数量:<span id="number">{{book.number}}</span>
</div>
<div>
<button v-on:click="addOne">加1</button>
<button v-on:click="minusOne">减1</button>
<button v-on:click="reset">归零</button>
</div>
</div>
`,
created(){
model.fetch(1).then(()=>{
this.book = model.data
})
},
methods: {
addOne: function(){
model.updata(1,{number: this.book.number + 1}).then(()=>{
this.book = model.data;
})
},
minusOne: function(){
model.updata(1,{number: this.book.number - 1}).then(()=>{
this.book = model.data;
})
},
reset: function(){
model.updata(1,{number: 0}).then(()=>{
this.book = model.data;
})
}
}
})
使用vue实现上面案例的完整代码:
JS Binjsbin.com