一.响应式数据之数组的处理
<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还是https
const 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或reject
if (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; } }