IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    实现一个简单版vue3-like module

    Kingfish404发表于 2021-06-01 00:00:00
    love 0

    关于Vue,可以去看其官方文档Vue,Evan You yyds。

    用ES6语法实现的vue-like,可能在部分浏览器上有兼容性问题,不过这个用Babel简单翻译一下就好,问题不大。

    写的可能有点小问题,暂时还没有直接的去读过Vue的源码,只是了解其单向/双向数据原理,虚拟dom,Diff算法及更新优化算法等,我接手的前端工程化项目用的也主要是是用react来写,所以我就直接用react中组件的思想来设计这个vue-like了(所以是不是应该叫vueact?)。

    程序设计

    这个module的运行流程就是

    1. import Vue from 'base_url/vue-like.js'
    2. Vue
      .createApp({ data ,method ,template })
      .mount('选择器')
    3. 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



沪ICP备19023445号-2号
友情链接