关于Vue,可以去看其官方文档 Vue,Evan You yyds。
用ES6
语法实现的vue-like
,可能在部分浏览器上有兼容性问题,不过这个用Babel
简单翻译一下就好,问题不大。
写的可能有点小问题,暂时还没有直接的去读过Vue
的源码,只是了解其单向/双向数据原理,虚拟dom,Diff
算法及更新优化算法等,我接手的前端工程化项目用的也主要是是用react
来写,所以我就直接用react
中组件的思想来设计这个vue-like
了(所以是不是应该叫vueact?)。
程序设计 #
这个module
的运行流程就是
import Vue from 'base_url/vue-like.js'
Vue
.createApp({ data ,method ,template })
.mount('选择器')
loop
:检测是否有method
触发了set
,有的话则对对应App
重新render
Vue
是在module
中实例化的对象,其createApp
方法接收一个创建参数对象,并将其保存为自身属性
mount
方法根据输入的css
选择器字符串(如#root
表示id
为root
的html
标签),选择对应的根对象生成并加入构造的App
对象。
Vue
的所有方法均支持carry
化调用,也可以分行调用。
功能实现 #
单向数据绑定的实现,ES6语法的代理Proxy
与反射Reflect
,对data
中每个对象的get
和set
方法进行代理,有点像切面注入了。
这里的代码其实很简单,ES6为我们自带提供了Proxy
对象,Reflect
作为当前绑定的对象对镜像执行原有预期操作。
this.data = new Proxy(this.data, {
get: function (target, propKey, receiver) {
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
// console.log(arguments);
if (target[propKey] == value) { // 非引用对象值未修时的简单优化
return true;
}
if (Reflect.set(target, propKey, value, receiver)) {
that.render(); // 重新render
return true;
}
return false;
}
})
简易dom生成我就暂时没有写复杂的虚拟dom
的Diff
算法了,而是set
对象如果发现data
中的元素值被修改的话,直接触发当前APP
的render
进行整体重新渲染。
实际的实现中,是用一个类成员函数来解析templete data
,生成一个真实的dom
对象。
templete data
如下
Vue.h('h1', {
onclick: 'decrease' // attribute,props 的name和对应methods中的函数/data中的值名
}, "App1: {{ counter }} click to increase")
实际效果 #
实际部署后预览如下,放在GitHub Page上,国内可能出现加载不出来的情况:
调用方式 #
上面例子中的App1,调用方式如下,App2的各位也可以自行右键>检查或者f12查看源码。我加入了一些方便自己开发的跳转,总的来说和vue3的非模板调用方式还是差不多的。
<div class="app1"></div>
import Vue from './vue-like.js';
const appData1 = {
data: {
counter: 0
},
methods: {
increase() {
this.counter++;
},
decrease() {
this.counter--;
},
},
render: Vue.h('h1', {
onclick: 'decrease'
// 这里由于jekyll的字符冲突,我被迫加了转义字符'\'
}, "App1: \{\{ counter \}\} click to increase")
}
Vue.createApp(appData1).mount('.app1');
源码 #
源码我放在了我的GitHub仓库上, https://github.com/Kingfish404/lib-practice/blob/master/vue3-like/vue-like.js