vue2.x 對(duì)象劫持的原理實(shí)現(xiàn)
目標(biāo):手寫(xiě)迷你版Vue
一:使用rollup打包,打包后的代碼體積更小,更適合寫(xiě)框架源碼的打包
npm i rollup -D
二:安裝babel相關(guān)的包,以及實(shí)現(xiàn)靜態(tài)服務(wù),設(shè)置環(huán)境變量的包
npm i @babel/core @babel/preset-env rollup-plugin-babel roullup-plugin-serve cross-env -D
三:包的相關(guān)介紹
- rollup (打包工具)
- @babel/core(用babel核心模塊)
- @babel/preset-env(babel將高級(jí)語(yǔ)法轉(zhuǎn)成低級(jí)語(yǔ)法)
- rollup-plugin-serve(實(shí)現(xiàn)靜態(tài)服務(wù))
- cross-env(設(shè)置環(huán)境變量)
- rollup-plugin-babel(橋梁)
四:根目錄書(shū)寫(xiě)rollup.config.js
import babel from 'rollup-plugin-babel';
import serve from 'rollup-plugin-serve';
export default {
input:'./src/index.js', // 以哪個(gè)文件作為打包的入口
output:{
file:'dist/umd/vue.js', // 出口路徑
name:'Vue', // 指定打包后全局變量的名字
format: 'umd', // 統(tǒng)一模塊規(guī)范
sourcemap:true, // es6-> es5 開(kāi)啟源碼調(diào)試 可以找到源代碼的報(bào)錯(cuò)位置
},
plugins:[ // 使用的插件
babel({
exclude:"node_modules/**"
}),
process.env.ENV === 'development'?serve({
open:true,
openPage:'/public/index.html', // 默認(rèn)打開(kāi)html的路徑
port:3000,
contentBase:''
}):null
]
}
配置package.josn
{
"name": "vue_souce",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build:dev": "rollup -c",
"serve": "cross-env ENV=development rollup -c -w"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"cross-env": "^7.0.2",
"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-serve": "^1.0.1"
}
}
五:新建index.html(public/index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="/dist/umd/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
// 隨便給些數(shù)據(jù)
data(){
return {
name:'張三',
age:11,
address:{
number:0,
name:'李四'
}}
},
})
vm._data.address = {a:1};
console.log(vm._data)
</script>
</body>
</html>
六:編寫(xiě)Vue入口:index.js
// Vue的核心代碼 只是Vue的一個(gè)聲明
import {initMixin} from './init';
function Vue(options){
// 進(jìn)行Vue的初始化操作
this._init(options);
}
// 通過(guò)引入文件的方式 給Vue原型上添加方法
initMixin(Vue); // 給Vue原型上添加一個(gè)_init方法
export default Vue
七:編寫(xiě)初始化操作 init.js
import {initState} from './state'
// 在原型上添加一個(gè)init方法
export function initMixin(Vue){
// 初始化流程
Vue.prototype._init = function (options) {
// 數(shù)據(jù)的劫持
const vm = this; // vue中使用 this.$options 指代的就是用戶(hù)傳遞的屬性
vm.$options = options;
// 初始化狀態(tài)
initState(vm); // 分割代碼
}
}
八:初始化數(shù)據(jù)
import {observe} from './observer/index.js'
export function initState(vm){
const opts = vm.$options;
// vue的數(shù)據(jù)來(lái)源 屬性 方法 數(shù)據(jù) 計(jì)算屬性 watch
if(opts.props){
initProps(vm);
}
if(opts.methods){
initMethod(vm);
}
if(opts.data){
initData(vm);
}
if(opts.computed){
initComputed(vm);
}
if(opts.watch){
initWatch(vm);
}
}
function initProps(){}
function initMethod() {}
function initData(vm){
// 數(shù)據(jù)初始化工作
let data = vm.$options.data; // 用戶(hù)傳遞的data
data = vm._data = typeof data === 'function'?data.call(vm):data;
// 對(duì)象劫持 用戶(hù)改變了數(shù)據(jù) 我希望可以得到通知 =》 刷新頁(yè)面
// MVVM模式 數(shù)據(jù)變化可以驅(qū)動(dòng)視圖變化
// Object.defineProperty () 給屬性增加get方法和set方法
observe(data); // 響應(yīng)式原理
}
function initComputed(){}
function initWatch(){}
九:書(shū)寫(xiě)核心監(jiān)聽(tīng)功能
// 把data中的數(shù)據(jù) 都使用Object.defineProperty重新定義 es5
// Object.defineProperty 不能兼容ie8 及以下 vue2 無(wú)法兼容ie8版本
import {
isObject
} from '../util/index'
// 后續(xù)我可以知道它是不是一個(gè)已經(jīng)觀察了的數(shù)據(jù) __ob__
class Observer{
constructor(value){ // 僅僅是初始化的操作
// vue如果數(shù)據(jù)的層次過(guò)多 需要遞歸的去解析對(duì)象中的屬性,依次增加set和get方法
// 對(duì)數(shù)組監(jiān)控
this.walk(value); // 對(duì)對(duì)象進(jìn)行觀測(cè)
}
walk(data){
let keys = Object.keys(data); // [name,age,address]
// 如果這個(gè)data 不可配置 直接return
keys.forEach((key)=>{
defineReactive(data,key,data[key]);
})
}
}
function defineReactive(data,key,value){
observe(value); // 遞歸實(shí)現(xiàn)深度檢測(cè)
Object.defineProperty(data,key,{
configurable:true,
enumerable:false,
get(){ // 獲取值的時(shí)候做一些操作
return value;
},
set(newValue){ // 也可以做一些操作
if(newValue === value) return;
observe(newValue); // 繼續(xù)劫持用戶(hù)設(shè)置的值,因?yàn)橛锌赡苡脩?hù)設(shè)置的值是一個(gè)對(duì)象
value = newValue;
}
});
}
export function observe(data) {
let isObj = isObject(data);
if (!isObj) {
return
}
return new Observer(data); // 用來(lái)觀測(cè)數(shù)據(jù)
}
十:編寫(xiě)工具類(lèi)文件,存放校驗(yàn)對(duì)象
/**
*
* @param {*} data 當(dāng)前數(shù)據(jù)是不是對(duì)象
*/
export function isObject(data) {
return typeof data === 'object' && data !== null;
}
總結(jié):
1 創(chuàng)建Vue構(gòu)造函數(shù),接收所有所有參數(shù)options
2 分類(lèi)初始化options,本章主要處理data,讓data上的引用類(lèi)型的數(shù)據(jù)通過(guò)Object.definePrototy 變成響應(yīng)式的,初始化是有循序的,先初始化props 然后初始化method 然后初始化data computed watch
3 核心如下
function defineReactive(data,key,value){
observe(value); // 遞歸實(shí)現(xiàn)深度檢測(cè)
Object.defineProperty(data,key,{
configurable:true,
enumerable:false,
get(){ // 獲取值的時(shí)候做一些操作
return value;
},
set(newValue){ // 也可以做一些操作
if(newValue === value) return;
observe(newValue); // 繼續(xù)劫持用戶(hù)設(shè)置的值,因?yàn)橛锌赡苡脩?hù)設(shè)置的值是一個(gè)對(duì)象
value = newValue;
}
});
}
到此這篇關(guān)于vue2.x 對(duì)象劫持的原理實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue2.x 對(duì)象劫持內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue?element-ui?el-cascader?只能末級(jí)多選問(wèn)題
這篇文章主要介紹了Vue?element-ui?el-cascader?只能末級(jí)多選問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
關(guān)于SpringBoot與Vue交互跨域問(wèn)題解決方案
最近在利用springboot+vue整合開(kāi)發(fā)一個(gè)前后端分離的個(gè)人博客網(wǎng)站,所以這一篇總結(jié)一下在開(kāi)發(fā)中遇到的一個(gè)問(wèn)題,關(guān)于解決在使用vue和springboot在開(kāi)發(fā)前后端分離的項(xiàng)目時(shí),如何解決跨域問(wèn)題。在這里分別分享兩種方法,分別在前端vue中解決和在后臺(tái)springboot中解決。2021-10-10
vue項(xiàng)目的html如何引進(jìn)public里面的js文件
這篇文章主要介紹了vue項(xiàng)目的html如何引進(jìn)public里面的js文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
vue基于viewer實(shí)現(xiàn)的圖片查看器功能
這篇文章主要介紹了vue基于viewer實(shí)現(xiàn)的圖片查看器的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
vue中el-date-picker選擇日期的限制的項(xiàng)目實(shí)踐
ElementUI的el-date-picker使用時(shí),有時(shí)候想要限制用戶(hù)選擇的時(shí)間范圍,本文就來(lái)介紹了vue中el-date-picker選擇日期的限制的項(xiàng)目實(shí)踐,感興趣的可以了解一下2023-10-10
vue3項(xiàng)目中代碼出現(xiàn)紅色波浪線的問(wèn)題及解決
這篇文章主要介紹了vue3項(xiàng)目中代碼出現(xiàn)紅色波浪線的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09

