1. 虚拟 DOM 原理

http://www.cnblogs.com/lvyongbo/p/5931636.html

单向数据流和双向数据流区别

说到底就是 (value 的单向绑定 + onChange 事件侦听)的一个语法糖,你如果不想用 v-model,像 React 那样处理也是完全可以的。
单向数据流和双向数据流

2. 深扒

强烈推荐:双向数据绑定的 3 种实现方式
读懂源码:一步一步实现一个 Vue
响应式绑定参考
virtual dom 和 diff 算法参考
理解 vue 实现原理,实现一个简单的 Vue 框架
vue 源码分析之如何实现 observer 和 watcher
vue 的 diff 算法学习

3. 总结

1.observe:主要是通过遍历 Object.defineProperty 为每个属性添加 get 和 set 方法 2.监听队列:

1
2
3
4
5
6
7
8
9
10
11
export default class Dep {
constructor() {
this.subs = [] //这个就是监听队列的数组
}
addSub(sub){
this.subs.push(sub) //将要监听的属性放进去
}
notify(){
this.subs.forEach(sub=>sub.update()) //在属性的set方法里会触发notify方法,进行遍历这些被监听或变化了的属性,进行dom更新
}
}
  1. 订阅者–分辨是主动触发还是自动触发
    单线程,当调用 watch 的时候会触发调用 get,这时候先标记一个全局变量,然后在普通属性里会判断是否含有这个变量,有的话就是自动触发,没有的话就是手动调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
export default class Watcher {
....省略未改动代码....
get(){
Dep.target = this
//此处简化。。要区分fuction还是expression
const value = this.vm._data[this.expOrFn]
Dep.target = null
return value
}
}
export function defineReactive (obj, key, val) {
var dep = new Dep()
var childOb = observe(val)

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{
// 说明这是watch 引起的
if(Dep.target){
dep.addSub(Dep.target)
}
return val
},
set:newVal=> {
var value = val
if (newVal === value) {
return
}
val = newVal
childOb = observe(newVal)
dep.notify()
}
})
}

4.自定义插件

5.directive 用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

//var app = document.createElement('app');
//document.getElementsByTagName('div')[0].appendChild(app);
Vue.component('abc', {
template: '<div>abc content</div>'
});

Vue.directive('tip', {
bind: function() {
console.log('bind');
},
inserted: function(el) {
var abc = document.createElement('abc');
el.appendChild(abc);
new Vue({
el: el
});
console.log('inserted');
},
update: function() {
console.log('update');
},
componentUpdated: function() {
console.log('componentUpdated');
},
unbind: function() {
console.log('unbind');
}
})

Vue.component('app', {
beforeCreate: function() {
console.log('beforeCreate')
},
created: function() {
console.log('created')
},
beforeMount: function() {
console.log('beforeMount')
},
mounted: function() {
console.log('mounted')
},
beforeUpdate: function() {
console.log('beforeUpdate')
},
updated: function() {
console.log('updated')
},
activated: function() {
console.log('activated')
},
deactivated: function() {
console.log('deactivated')
},
beforeDestroy: function() {
console.log('beforeDestroy')
},
destroyed: function() {
console.log('destroyed')
},
template: '<div>test app content</div>'
});

new Vue({
created: function() {
//document.getElementsByTagName('div')[0].appendChild(app);
},
el: 'div'
});

6.Vue.component 的 Vue.extend 的区别

Vue.extend 写法

1
2
3
var newDemo = Vue.extend(Demo); //是个函数
//将函数转化为DOM
new newDemo().$mount().$el;

Vue.component 写法

1
2
3
4
Vue.component('demo', Demo); //设置demo
var newDemo = Vue.component('demo'); //取出demo 是个函数
//将函数转化为DOM
new newDemo().$mount().$el;

vue-resource

1
2
3
4
5
6
7
8
9
10
11
12
13
// 全局
Vue.http.options.root = 'http://zhuanzhuan.58.com/zz/transfer'; // 交互请求的根目录地址
Vue.http.options.xhr = { withCredentials: true }; //XMLHttpRequest.withCredentials 开启CORS
Vue.http.options.credentials = true; // 也是开启CORS
Vue.http.interceptors.push((request, next) => {}); //自定义拦截器,预处理和后处理的要求

// 局部独立定义
export const replaycomment = (params) => {
return Vue.http.post(API.REPLAY_COMMENT, params, {
credentials: true,
emulateJSON: true,
});
};

参考文档

this 丢失

像 ajax 等异步操作,会丢失 this,而取不到属性值
避免方法:使用箭头函数

Vue 改变数组时,属性不监听

用 slice 先取出来

1
this.cateIdArr = this.getCateIdArr.slice();

不要同时监听

下边这两个是有区别的!!
computed是计算:别的数据改变,这个属性计算
watch是监听
不要一个属性在两个里都写,否则返回 undefined

v-model 返回值

数据类型为字符串
所以只有""时为假,其他都为真

父组件与子组件通信

没有用 v-bind 传入的是字符串
用了 v-bind 传入的就是一个 js 表达式

1
2
3
4
<!-- 传递了一个字符串"1" -->
<comp some-prop="1"></comp>
<!-- 传递实际的数字 -->
<comp v-bind:some-prop="1"></comp>

#子组件内操作,同时父组件同时改变
父组件传过来的数据可以是一个对象,
在子组件对该对象进行修改,
被修改的同时也会修改父组件的数据了
参考

CORS 跨域问题

服务器端开启

1
2
Access-Control-Allow-Credentials: true     // 开启coockie验证
Access-Control-Allow-Origin: http://m.zhuanzhuan.58.com

Vue 设置

1
2
3
4
Vue.http.interceptors.push((request, next) => {
request.credentials = true; // 开启传cookie
next((response) => {});
});

vue-resource progress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
this.$http
.post(url, data, {
progress: function (event) {
if (event.lengthComputable) {
let percentComplete = Math.round((event.loaded * 100) / event.total); // evt.loaded已经上传了的 evt.total 总共大小
console.log(percentComplete.toString() + '%');
} else {
console.log('不支持');
}
},
})
.then((response) => {
console.log(JSON.parse(res.body));
});

vue 无法监听到最开始属性值是 undefined 的属性

必须在 data 内先声明,才能进行监听

vuex 注意

1.修改状态必须通过 mutations/actions 修改,否则报错 2.用 v-model 的时候是双向绑定,vuex 并不是,需要将需要监听的值设成双向绑定

6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
computed: {
...mapGetters([
'commentData',
'replyParam',
'askParam',
'answerParam',
'sheetActions'
]),
sheetVisible: { // 因sheetAction用了v-model 所以需要进行双向绑定
// getter
get: function () {
return this.$store.state.commentDetail.sheetVisible;
},
// setter
set: function (newValue) {
this.changeSheetVisible(newValue); // 必须通过mutations修改
}
}
},

写法:

1
2
3
4
5
const store = new Vuex.Store({ modules: { account: { namespaced: true, // module
assets state: { ... }, // module state is already nested and not affected by
namespace option getters: { isAdmin () { ... } // -> getters['account/isAdmin']
}, actions: { login () { ... } // -> dispatch('account/login') }, mutations: {
login () { ... } // -> commit('account/login') } } } })

Vue Cli 深入认识

深入认识 vue-cli:能做的不仅仅是初始化 vue 工程
vue-cli 简介(中文翻译)
vue-cli 是如何工作的

监听对象内属性的变化

1
2
3
4
5
6
7
8
9
10
computed: {
newIndex () {
return this.swipeData.index;
}
},
watch: {
newIndex () {
this.scrollTo(this.swipeData.index);
}
},

思想:曲线救国,先计算,再监听这个计算值的变化

keep-alive 记录高度

vue-router 实现
vue 使用 keep-alive 保持滚动条位置的实现

1
2
3
4
5
6
7
8
9
10
11
12
const router = new Router({
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 };
}
},
mode: 'history',
base: '/u/zzlease/',
routes,
});

接入 ts

用 TypeScript 来写 Vue!
vue + typescript 新项目起手式
一起来拥抱强大的 TypeScript 吧

指令详解

vue 自定义指令 VNode 详解
官方文档

原理文章

keep-alive实现原理
面向源码研究Nuxt.js

← Prev Next →