上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

【油猴开发指南】Vue3的常见数据位置与触发响应

[复制链接]
  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5959

    回帖

    6758

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6758

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2024-10-18 08:07:40 | 显示全部楼层 | 阅读模式

    Vue3的开发方式不再使用Vue2的选项式
    这个时候数据来源以及修改就成了问题
    我们可以创建一个最简单的实例来作为分析例子

        const { createApp, ref } = Vue;
    createApp({
      setup() {
        debugger;
        const message = ref("Hello vue!");
        return {
          message,
        };
      },
      created() {
          console.log("created")
      },
    }).mount("#app");

    针对setup函数打端点,通过堆栈回溯可以找到setupStatefulComponent函数进行调用
    其中可以看到首先从Component组件的模板中获得了Setup,然后通过callWithErrorHandling函数来防止setup出错进行调用

          const { setup } = Component;
          if (setup) {
            pauseTracking();
            const setupContext = instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null;
            const reset = setCurrentInstance(instance);
            const setupResult = callWithErrorHandling(
              setup,
              instance,
              0,
              [
                shallowReadonly(instance.props) ,
                setupContext
              ]
            );
        }

    其中最后一部分是setup传入的参数,我们可以发现
    其中组件的setup函数的props数据来自于实例的instance.props通过一层shallowReadonly做浅包裹
    而contexnt来自于instance.setupContext包含了emit,expose,attrs,slots四个参数,但是如果setup的参数没有进行使用不会进行创建

    我们继续往下走可以走到handleSetupResult函数中
    其中可以发现如果是函数则将作为render模板,而如果为对象则会设置到实例的setupState上

        function handleSetupResult(instance, setupResult, isSSR) {
          if (isFunction(setupResult)) {
            {
              instance.render = setupResult;
            }
          } else if (isObject(setupResult)) {
            instance.setupState = proxyRefs(setupResult);
          }

    而我们混入的this属性,根据调试可以确定实例在this的_属性上,由此可以推断出以下常见数据所在位置

      //setup数据  this['_'].setupState
      //data数据   this['_'].$data
      //render数据 this['_'].render
      //props数据  this['_'].props

    关于修改数据,其中setupState最简单,他是通过ref函数创建的,而ref最后创建的是RefImpl的类实例对象,根据代码可知直接设置value属性即可

        class RefImpl {
          constructor(value, isShallow2) {
            this.dep = new Dep();
            this["__v_isRef"] = true;
            this["__v_isShallow"] = false;
            this._rawValue = isShallow2 ? value : toRaw(value);
            this._value = isShallow2 ? value : toReactive(value);
            this["__v_isShallow"] = isShallow2;
          }
          get value() {
            {
              this.dep.track({
                target: this,
                type: "get",
                key: "value"
              });
            }
            return this._value;
          }
          set value(newValue) {
            const oldValue = this._rawValue;
            const useDirectValue = this["__v_isShallow"] || isShallow(newValue) || isReadonly(newValue);
            newValue = useDirectValue ? newValue : toRaw(newValue);
            if (hasChanged(newValue, oldValue)) {
              this._rawValue = newValue;
              this._value = useDirectValue ? newValue : toReactive(newValue);
              {
                this.dep.trigger({
                  target: this,
                  type: "set",
                  key: "value",
                  newValue,
                  oldValue
                });
              }
            }
          }
        }

    需要注意的是,Vue3中data属性是选项式data函数所返回的,而setup返回的是setupState属性,二者不能混为一谈,由于data其修改方式类似,暂且就不表了
    除此之外还有一个props属性,props只有最顶层的数据触发才能进行修改,不能单纯的修改某个属性内容,例如

    instance.props.info={...instance.props.info,title:"123456"}

    才可以成功触发数据响应
    而render一般不推荐进行修改,暂且就不表了~

    结语

    撒花~

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    慵懒
    2023-5-5 13:37
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    117

    主题

    405

    回帖

    711

    积分

    版主

    积分
    711

    油中2周年油中3周年

    发表于 2024-10-19 22:28:16 | 显示全部楼层
    ggnb
    提及少年一词,应与平庸相斥!
    回复

    使用道具 举报

  • TA的每日心情
    开心
    10 小时前
  • 签到天数: 41 天

    [LV.5]常住居民I

    5

    主题

    22

    回帖

    56

    积分

    初级工程师

    积分
    56

    油中3周年挑战者 lv2

    发表于 2024-11-4 17:58:59 | 显示全部楼层
    道哥 生产模式下setupState 是空的 是没办法拿到数据吗
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5959

    回帖

    6758

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6758

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2024-11-4 18:11:15 | 显示全部楼层
    krystal 发表于 2024-11-4 17:58
    道哥 生产模式下setupState 是空的 是没办法拿到数据吗

    setup返回render是存在闭包的
    setupState按道理是应该为空对象
    从理论上来说vue需要diff,按道理也存在数据的注入位置
    但是这部分我还没有研究
    可能需要从vnode方面下手

    目前vite/webpack5/vue3的常用注入位置都还没搞完

    道阻且长啊


    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表