vue-next项目地址
git地址:链接
git clone git@github.com:vuejs/vue-next.git
npm install
npm run dev // 生成一个未压缩的状态vue文件
入门小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.global.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
const { createApp,reactive,computed,effect } = Vue;
const YpComponent = {
template:`
<button @click="increment">Count is {{state.count}} double:{{state.double}}</button>
`,
setup(){
const state = reactive({
count:0,
double:computed(()=>state.count*2)
})
effect(()=>{
// 副作用 可以监听变化
console.log('数字变化了',state.count)
})
function increment(){
state.count+=1
}
return {
state,
increment
}
}
}
createApp().mount(YpComponent,'#app')
</script>
</body>
</html>
自己写一个reactive,computed,effect
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./my-vue.js"></script>
</head>
<body>
<div id="app"></div>
<button id="btn">点我</button>
<script>
const root = document.querySelector('#app')
const btn = document.querySelector('#btn')
const obj = reactive({
name: "vue",
age: 6
})
let double= computed(()=>obj.age*2)
effect(() => {
root.innerHTML = `<h1>${obj.name}版本${obj.age} double:${double.value}</h1>`
})
btn.addEventListener('click', () => {
obj.age += 1
}, false)
</script>
</body>
</html>
my-vue.js
let toProxy = new WeakMap() //存储 原始--响应
let toRaw = new WeakMap() //存储 响应--原始
const baseHander = {
get(target, key) {
const res = Reflect.get(target, key)
//收集依赖
track(target, key)
// 递归查找
return typeof res === 'object' ? reactive(res) : res
},
set(target, key, val) {
const info = {
oldValue: target[key],
newValue: val
}
// if(target.hasOwnProperty(key)){ // 即如果触发的是私有属性,可以直接触发视图更新,length会屏蔽掉
// trigger();
// }
const res = Reflect.set(target, key, val)
// 触发更新
trigger(target, key, info)
return res
}
}
function reactive(target) {
// 查询缓存
let observed = toProxy.get(target)
if (observed) {
return observed;
}
if (toRaw.get(target)) {
return target
}
observed = new Proxy(target, baseHander)
//设置缓存
toProxy.set(target, observed)
toRaw.set(observed, target)
return observed
}
let effectStack = []
let tagetMap = new WeakMap() //存储effect
function trigger(target, key, info) {
const depsMap = tagetMap.get(target)
if (depsMap === undefined) {
return
}
const effects = new Set()
const computedRuners = new Set()
if (key) {
let deps = depsMap.get(key)
deps.forEach((effect) => {
if(effect.computed){
computedRuners.add(effect)
}else{
effects.add(effect)
}
})
}
// const run = effect =>effect()
effects.forEach(effect => effect())
computedRuners.forEach(effect => effect())
}
function track(target,key) {
let effect = effectStack[effectStack.length - 1]
if (effect) {
let depsMap = tagetMap.get(target)
if (depsMap === undefined) {
depsMap = new Map()
tagetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (dep === undefined) {
dep = new Set()
depsMap.set(key, dep)
}
if (!dep.has(effect)) {
dep.add(effect)
effect.deps.push(dep)
}
}
}
function effect(fn, options={}) {
let e = createReactiveEffect(fn, options)
if(!options.lazy){
e()
}
return e
}
function createReactiveEffect(fn, options) {
const effect = function effect(...args) {
return run(effect, fn, args)
}
effect.deps = []
effect.computed = options.computed
effect.lazy = options.lazy
return effect
}
function run(effect, fn, args) {
if (effectStack.indexOf(effect) === -1) {
try {
effectStack.push(effect)
return fn(...args)
} finally {
effectStack.pop()
}
}
}
function computed(fn) {
const runner = effect(fn,{computed:true,lazy:true})
return {
effect:runner,
get value(){
return runner()
}
}
}