• 手把手实现简易版vue(二)组件类解析


    1、构造器

    1. constructor(propsArgus = {}) {
    2. const {
    3. data = () => {},
    4. methods = {},
    5. watch = {},
    6. computed = {}, // 待实现
    7. props = {}, // 待实现
    8. created = () => {}, // created钩子函数
    9. mounted = () => {}, // mounted钩子函数
    10. destroyed = () => {} // destroyed钩子函数
    11. } = propsArgus
    12. this.$watch = watch // watch方法集合
    13. this.$watchers = {} // 收集器集合
    14. this.$methods = methods // 执行方法集合
    15. this.$data = data() || {} // 数据定义集合
    16. this.$computed = computed // 计算属性集合 待开发
    17. this.$props = props // 传递属性集合
    18. this.$created = created // created生命周期注入
    19. this.$mounted = mounted // mounted生命周期注入
    20. this.$destroyed = destroyed // destroyed生命周期注入
    21. bindProperties(this, this.$data)
    22. this.observe(this)
    23. bindProperties(this, this.$methods)
    24. this.$created() // created钩子执行 在dom挂载之前执行
    25. }

    2、属性方法讲解及示例

    1、data

    写法是不是跟vue2一样啊,都是函数返回对象形式

    1. data: () => {
    2. return {
    3. article: {
    4. title: '前标题',
    5. text: {
    6. word: '文字'
    7. }
    8. },
    9. author: '前林大大哟'
    10. };
    11. }

    2、methods

    方法对象,跟vue2写法一致

    1. methods: {
    2. onButtonClick() {
    3. this.article.title = "标题"
    4. this.author = '林大大哟'
    5. },
    6. itemClick(item, type) {
    7. console.log(item, type);
    8. }
    9. }

    3、watch

    监听引用类型和基本类型,但写法都是一致的,和vue2不同的是并没有对对象内部单个值进行监听

    1. watch: {
    2. author(value) {
    3. console.log("watch 监听author:", value);
    4. },
    5. article(value){
    6. console.log("watch 监听 article.title:", value);
    7. }
    8. }

    4、created, mounted, destroyed

    这三个生命周期都和vue2用法一致,内部核心如下,这一点我倒是没有参考任何东西,根据自己想法写的~

    3、核心源码讲解

    数据响应式,是mvvm架构核心,vue2用的是Object.defineProperty,vue用的是Proxy,那我将这两者结合起来用,引用类型我用Proxy监测,基本类型我用Object.defineProperty监测

    源码如下,都是遍历data中的数据,当发现是基本类型时候,用Object.defineProperty转换成响应式类型,而updateWatcher方法,就是被动触发页面结构中包含这数据的dom,然后让他进行更新(这部分vue源码中清除解释了,将同一数据的dom都放进收集器中,当此数据需要更新时,则通知收集器中的各个dom进行依赖更新),而watch对象中有监听这数据的话,就主动的去触发watch中的方法:data.$watch[key].call(data, val)。

    1. /**
    2. * 转换观测模式
    3. * @param {*} data 当前作用指针
    4. * @returns
    5. */
    6. observe (data) {
    7. if (!data || getDataType(data) !== 'object') { // 按顺序写一般都不会进入这一步 用于初始化
    8. return
    9. }
    10. const arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']
    11. const keys = Object.keys(this.$data)
    12. for (let key of keys) {
    13. let value = data[key]
    14. if (getDataType(value) === 'object' ||
    15. getDataType(value) === 'array' ||
    16. getDataType(value) === 'null'
    17. ) {
    18. value = getDataType(value) === 'null' ? {} : value // Proxy不能传入不是对象的类型,所以在这里转一下
    19. data[key] = this.deepProxy(key, value)
    20. } else {
    21. Object.defineProperty(data, key, {
    22. configurable: false,
    23. enumerable: true,
    24. set(val) {
    25. value = val
    26. updateWatcher(this.$watchers[key], val) // 数据改变 watcher触发修改对应界面上的值
    27. if (data.$watch[key]) {
    28. data.$watch[key].call(data, val) // 主动触发watch对象的方法
    29. }
    30. },
    31. get() {
    32. return value
    33. }
    34. })
    35. }
    36. }
    37. }

     当发现是引用类型时候,就用Proxy转换此引用类型,当然至于LveProxy类是啥样,这个我下篇再来写,核心其实就是Proxy和Reflect

    1. /**
    2. * 深度遍历并转换为自定义Proxy代理
    3. * @param {*} obj
    4. * @returns
    5. */
    6. deepProxy(key, obj) {
    7. if (getDataType(obj) === 'array') { // 数组深度遍历
    8. obj.forEach((v, i) => {
    9. if (getDataType(obj) === 'object') {
    10. obj[i] = this.deepProxy(v)
    11. }
    12. })
    13. } else { // 对象深度遍历
    14. if (Object.keys(obj).length === 0) return
    15. Object.keys(obj).forEach(v => {
    16. if (getDataType(obj[v]) === 'object') {
    17. obj[v] = this.deepProxy(key, obj[v])
    18. }
    19. });
    20. }
    21. const proxy = new LveProxy(this, obj).init(key) // proxy代理
    22. return proxy
    23. }

    所以组件类的大体逻辑出来了,通过构造器将data,watch等这些传进去,然后mount到dom后,逻辑层和视图层就有了关联,逻辑层中数据以data中的为主,在dom中有关于data中的数据,都会被加入对应的收集器中(依赖收集),当data有数据更改,会将收集器中的依赖进行统一更新(依赖更新),至此MVVM框架的核心也就出来了,当然至于Proxy和模板如何转换的,那我将在下一篇博客中讲解~

  • 相关阅读:
    Ubuntu 20.04 下DeepSDF环境配置笔记
    C# 移除链表元素
    深入理解迪米特法则(Law Of Demeter)
    无心剑中译伊玛·拉扎罗斯《新巨人·自由女神》
    将jar添加到本地mvn仓库
    达梦数据库(十) -------- mybatis-plus 整合达梦时,自动生成的 sql 语句报错
    Android13保存文件到sdcard报错:Operation not permitted
    【LeetCode】25. 542_01 Matrix · 01矩阵
    洛谷100题DAY6
    实用电脑软件
  • 原文地址:https://blog.csdn.net/qq_39404437/article/details/134015707