1.SPA页面
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
2. keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 。
3. vuex原理
vuex是利用vue的mixin混入机制,在beforeCreate钩子前混入vuexInit方法,vuexInit方法实现了store注入vue组件实例,并注册了vuex store的引用属性$store。
Vuex的state状态是响应式,是借助vue的data是响应式,将state存入vue实例组件的data中;Vuex的getters则是借助vue的计算属性computed实现数据实时监听。
4.nextTick
由于VUE的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
触发时机:在同一事件循环中的数据变化后,DOM完成更新,立即执行nextTick(callback)内的回调。
主线程的执行过程就是一个tick,而所有的异步结果都是通过任务队列来调度的,无论是执行宏任务还是微任务,完成后都会进入到下一个tick,并在两个tick之间进行渲染。
同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback触发
5. 实现一个Observer
function observer(data) {
// 当不是对象的时候,退出
if (!data || typeof data !== 'object') {
return;
}
// 取出所有属性遍历
Object.keys(data).forEach(function(key) {
// 给每个属性加上get,set
defineReactive(data, key, data[key]);
});
};
function defineReactive(data, key, val) {
var dep = new Dep(); //实例化一个订阅器
observer(val); // 监听子属性
Object.defineProperty(data, key, {
enumerable: true, // 可遍历
configurable: false, // 不能修改,删除
get: function() {
// 如果这个属性存在,说明这是watcher 引起的
if(Dep.target){
// 那我调用dep.addSub把这个订阅者加入订阅器里面
dep.addSub(Dep.target)
}
return val;
},
set: function(newVal) {
if (val === newVal){return} //当前后数值相等,不做改变
val = newVal;
dep.notify(); //当前后数值变化,这时就通知订阅者了
console.log("已改变 "+newVal);
}
});
}
function Dep() {
this.subs = [];//存放消息数组
}
Dep.prototype = {
addSub: function(sub) { //增加订阅者函数
this.subs.push(sub);
},
notify: function() { //发布消息函数
this.subs.forEach(function(sub) {
sub.update(); //这里是订阅者的更新方法
});
}
};
一个双向绑定的实例:
6.用原生JS实现v-show指令
大致思路:
- 获取 div 上的指令(属性)以及指令的初始值;
- 定义能切换显示隐藏 div 的 dom 操作(视图刷新)方法;
- 劫持指令对应数据的 setter,setter 触发时调用 2 中的视图刷新。
<div class="box" v-show="isShow">Hello World!</div>
<button class="ui-button ui-button-primary" onClick="model.isShow = true">显示</button>
<button class="ui-button ui-button-primary" onClick="model.isShow = false">隐藏</button>
<script>
// 第 1 步: 定义数据和视图
var model = {
isShow: true
}
var view = document.querySelector('div')
// 第 2 步: 定义视图刷新方法
var updateView = function(value) {
view.style.display = value ? '' : 'none'
}
// 第 3 步: 设置初始视图表现
var directiveKey = view.getAttribute('v-show')
updateView(model[directiveKey])
// 第 4 步: 监听数据变化,然后刷新视图,达到数据驱动的目的
Object.defineProperty(model, 'isShow', {
set: function(val) {
updateView(val)
}
})
</script>