一.响应式数据之数组的处理
<template><div><ul><li v-for="(item, index) in items" :key="index">{{ item }}<button @click="removeItem(index)">Remove</button></li></ul><input v-model="newItem" @keyup.enter="addItem"><button @click="addItem">Add</button></div>
</template><script>
export default {data() {return {items: ['Apple', 'Banana', 'Cherry'],newItem: ''}},methods: {addItem() {if (this.newItem.trim()) {this.items.push(this.newItem.trim());this.newItem = '';}},removeItem(index) {this.items.splice(index, 1);}}
}
</script>
二.nextTick异步更新队列
nextTick是Vue框架中的一个重要概念,它利用了JavaScript的事件循环机制和异步回调任务队列来实现其功能,本质是对JavaScript执行原理EventLoop的一种应用。在Vue中,数据变化不会立即导致DOM更新,而是等到当前事件循环结束,统一进行视图更新。这就意味着,如果你在数据变化后立即访问DOM,你看到的仍然是更新前的DOM。
nextTick的实现原理是利用JavaScript的微任务机制,将回调函数添加到微任务队列中,确保在当前任务执行完成后立即执行微任务。当前任务完成后,JavaScript引擎会执行微任务队列中的任务,其中就包括nextTick添加的回调函数。这使得回调函数可以在DOM更新之后执行。
在Vue.js中,数据变化后会经历一个过程:
修改数据
视图更新(DOM更新)
nextTick的回调函数被执行
// 这是一个使用nextTick的例子
// 假设有一个Vue实例
new Vue({el: '#app',data: {message: 'Hello Vue!'}
});// 修改数据
this.message = 'Hello World!';// DOM还没有更新
this.$nextTick(() => {// DOM现在更新了// 我们可以执行依赖DOM的操作console.log(document.getElementById('app').textContent);
});
三.手写Vue核心代码
class Vue {constructor(options) {this.$el = document.querySelector(options.el);this.$data = options.data;// 初始化响应式系统this.observeData(this.$data);// 编译模板this.$el.innerHTML = this.compileTemplate(this.$el.outerHTML);// 挂载实例this.mount();}observeData(data) {if (typeof data !== 'object' || data === null) {return;}for (let key in data) {let dep = new Dep();let value = data[key];Object.defineProperty(data, key, {enumerable: true,configurable: true,get() {dep.addSub(Dep.target);return value;},set(newValue) {if (value === newValue) return;value = newValue;dep.notify();}});}}compileTemplate(template) {// 简单文本替换,例如 {{ message }} 替换为实例的响应式数据return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {return this.$data[key];});}mount() {// 挂载逻辑,例如将编译后的模板挂载到对应的DOM元素this.$el.innerHTML = this.compileTemplate(this.$el.outerHTML);}
}class Dep {constructor() {this.subs = [];}addSub(sub) {if (sub) {this.subs.push(sub);}}notify() {this.subs.forEach(sub => {sub.update();});}
}Dep.target = null; // 全局Dep.target,用于跟踪当前响应式依赖// 使用Vue
const app = new Vue({el: '#app',data: {message: 'Hello Vue!'}
});
四.Vue-Router核心源码解析
// Vue Router安装
npm install vue-router
// 以下是Vue Router的核心文件:
1.create-matcher.js:用于创建路由匹配器的工厂函数
2.create-route-map.js:用于创建路由映射的工厂函数
3.history.js:处理不同模式的History的API
4.index.js:Vue Router的入口文件,用于初始化Vue Router
5.install.js:用于Vue Router插件安装的工厂函数
6.location.js:处理URL解析和编码
7.route.js:定义路由记录的构造函数
8.router.js:定义Router类的构造函数
9.create-web-hash-history.js:创建使用hash模式的Web History
10.create-web-history.js:创建使用history模式的Web History
// 以下是一个简单的vue router使用示例
import Vue from 'Vue'
import VueRouter from 'vue-router'
import Home from './components/Home.vue'
import About from './components/About.vue'Vue.use(VueRouter);const routes = [{path: '/', component: Home},{path: '/about', component: About}
]const router = new VueRouter({mode: 'History',routes
})new Vue({router,template: '<div><h1>Vue Router Demo</h1><router-link to="/">Home</router-link><router-link to="/about">About</router-link><router-view></router-view></div>'
}).$mount('#app')
五.Vuex核心源码解析
Vuex是Vue.js应用的状态管理模式,Vuex的核心包括state、mutations、actions和getters
// 以下是 vuex核心概念的简化版核心源码解析// 模拟 Vuex 的 state
const state = {count: 0
}// 模拟 Vuex 的mutations
const mutations = {INCREMENT (state) {state.count++;}
}// 模拟 Vuex 的actions
const actions = {increment ({commit}) {commit('INCREMENT');}
}// 模拟Vuex的getters
const getters = {count: state => state.counet
}// 模拟 Vuex的store创建过程
const store = new Vuex.Store({state,mutations,actions, getters
})// 使用 store
store.dispatch('increment')
console.log(store.getters.count)
六.Axios核心源码解析
Axios是一个非常流行的javascript库,用于浏览器和node.js中发送HTTP请求。以下是一个简化的Axios核心功能的代码示例,展示了如何创建一个用于发送Http请求的简易版本:
// 引入axios依赖的库
const util = require('util');
const http = require('http');
const https = require('https');// 创建一个用于处理HTTP请求的函数
function axios(options) {// 返回一个Promise,允许异步处理return new Promise((resolve, reject) => {// 确定使用http还是httpsconst lib = options.protocol === 'http:' ? http : https;// 解析URL以提取主机名和端口const { hostname, port, path: pathname } = new URL(options.url);// 设置默认的端口const defaultPort = options.protocol === 'http:' ? 80 : 443;const portOrDefault = port || defaultPort;// 创建HTTP请求const req = lib.request({hostname,port: portOrDefault,path: pathname,method: options.method,headers: options.headers,}, (res) => {let data = '';// 接收数据片段res.on('data', (chunk) => {data += chunk;});// 请求完成res.on('end', () => {// 解析响应头const response = {status: res.statusCode,statusText: res.statusMessage,headers: res.headers,data: data,};// 解析数据(可以添加对JSON/其他格式的处理)try {response.data = JSON.parse(data);} catch (e) {response.data = data;}// 调用resolve或rejectif (res.statusCode >= 200 && res.statusCode < 300) {resolve(response);} else {reject(response);}});});// 错误处理req.on('error', (e) => {reject({status: null,statusText: e.message,headers: null,data: null});});// 可以添加超时处理等// 发送数据(如果有的话)if (options.data) {req.write(options.data);}// 结束请求req.end();});
}// 使用示例
axios({method: 'GET',url: 'http://example.com'
}).then(response => {console.log(response.data);
}).catch(error => {console.error(error.statusText);
});
七.Vue初始化流程
Vue 初始化主要涉及以下几个步骤:
1.创建Vue实例
new Vue({el: '#app',data: {message: 'Hello Vue!'} })
2.模板编译:Vue 将el选项中的DOM元素编译成渲染函数
3.数据观测: Vue使用Object.defineProperty来实现数据的响应式,并且在内部保存依赖。
4.编译模板: 将渲染函数与数据进行结合生成最终的DOM
5.挂载:将编译好的模板挂载到el选项指定的DOM上
6.更新DOM:当数据发生变化时,Vue的响应式系统会重新渲染虚拟DOM并对比差异,然后应用到真实DOM上。
八.Vue异步更新策略
在Vue中,响应式系统会尝试尽可能高效地更新Dom。为此,Vue提更了几种异步更新策略,以应对不同的场景。
1.nextTick:用于访问更新后的DOM。
Vue.nextTick(callback);
2.vm.$nextTick:实例方法,用于访问data更新后的DOM。
this.$nextTick(callback);
3.
v-for
中的key
:有助于Vue识别数组中哪些项被添加、删除或重新排序。<div v-for="item in items" :key="item.id">{{ item.text }} </div>
4.
v-if
、v-show
:根据条件渲染元素,v-if
是真正的条件渲染,因为它会确保条件块在值为false时不会出现在DOM中;v-show
则是简单地通过CSS切换。<div v-if="condition">...</div> <div v-show="condition">...</div>
5.
watch
:监听数据变化,并执行异步操作。watch: {someData: function (val, oldVal) {this.asyncMethod();} }
6.
watch
的immediate
和deep
选项:immediate
会在watcher被创建时立即触发,deep
会监控一个对象内部属性的变化。watch: {someObject: {handler: 'handlerMethod',immediate: true,deep: true} }
7.
computed
:计算缓存其结果,并且只有当依赖发生变化时才会重新计算。computed: {computedProperty: function () {return this.someOtherProperty + 1;} }