组件中使用响应式方法

107 阅读5分钟

组件中使用响应式方法,本节就介绍用法。

Vue的组成分为六大模块
编译层面的
        @vue/compiler-sfc
    | @vue/compiler-dom @vue/compiler-core
vue  // vue 直接引用的就是@vue/runtime-dom针对浏览器做了一些API,传递给了runtime-core,runtime-core 内部使用了@vue/reactivity 所以在VueRuntimeDom可以直接用响应式的内容 
    | @vue/runtime-dom @vue/runtime-core @vue/reactivity
运行时层面的
    @vue/runtime-dom 这个是依赖于@vue/runtime-core这个的 这个需要兼容不同的平台。
    @vue/runtime-core 这个是一个核心模块、不关心任何平台。
    @vue/reactivity
自己编写

package 创建

  • runtime-core/src/index.ts

    • yarn init -y
  • runtime-dom/src/indexts

    • yarn init -y
  • vue-core项目执行

    • yarn install

包名字起名字的学问

@vue/

为什么都用@vue因为都是一个组织的。相当于画了一个作用域。都在这里面

修改打包的配置 package.json
// @vue/runtime-dom
{
  "name": "@vue/runtime-dom",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "module": "dist/rumtime-dom.esm-bund.js",
  "buildOptions": {
    "name": "VueRuntimeDom",  
    "format": [
      // "cjs",  //因为这个玩意是在浏览器使用的这个就没啥必要留着了
      "esm-bund",    
      "global" // 这个是为了调试用的线留着
    ]
  }
}

// 这个被runtime-dom引用

{
  "name": "@vue/runtime-core",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "module": "dist/rumtime-core.esm-bund.js",
  "buildOptions": {
    "name": "VueRuntimeCore",  
    "format": [
      // "cjs",  //因为这个玩意是在浏览器使用的这个就没啥必要留着了
      "esm-bund",    
      // "global" // 这个是负责给dom用的就不考虑global了直接干掉
    ]
  }
}

// 在 vue-core下面执行
yarn install
把package/下面的包装到node_modules下面去
修改scripts/dev.js target 把测试的reactive 改成 runtime-dom[只打包runtime-dom]

先看看vue是怎么搞的

<div id="app"></div> // 挂在点

vue源代码
改改它的script/dev.js
reactive|vue 改成 runtime-dom 只打包我们的runtime-dom

创建example/test.html 看看是怎么渲染的

<script src="../dist/runtime-dom.global.js"></script>

// VueRuntimeDom

// VueRuntimeDom 这个是个组合式的

// runtime-dom 引用了 runtime-core 引用了 runtime-reactivity

// 在 VueRuntimeDom 这里是可以拿到reactive的

let {createApp, h, reactive} = VueRuntimeDom; // 创建应用 vue3 把h拿出来了 因为 runtime-dom 引用了 runtime-core 引用了 runtime-reactivity

// h 函数不在是回调了 可以直接结构出来。为了tree-shaking

// 不需要beforecreate 和 created 这两个玩意可以被setup所取代。这玩意放在vue2 data() 那个附近的结构也能用。 触发时机 setup -> beforecreate -> created


// 创建一个跟组件
let AppRoot = {
    // 接收属性
    props: {
        name: String,
    },
    // template模版最后也能变成render的形式
    // AppRoot 这个玩意如何有个入口?setup
    setup(props, context){
        // props属性对象
        // context 这个玩意是上下文 这里头有些什么内容?emit expose对外暴露的属性 插槽slots
        // reactive
        // ref
        // computed 都以这个为入口才能用
        // 它可以替换掉某些声明周期
        // 它替换掉了 beforeCreate
        
        const state = reactive({name:1});
        console.log(state.name);
        
        // 这里的这个数据怎么能放到h函数里面?
        // 直接把这个状态返回
        // 下面取值的时候会把data和返回的这个{}对象进行合并
        return {
            state,
        }
        
        // 第二种返回一个render函数
        //=========================================
        // 上面那个写法把state还返回比较恶心有个简单方式直接把下面的render去掉
        
        // 在这里返回
        
        const fn = () => {}
        
        return (proxy) => { // render函数是个effect state改变了会导致render重新执行
            // 这个作用域下可以直接用上面的state 比较方便
            console.log(proxy); // 可以拿到data methods里面这些内容。
            // 这里的这个this 是什么?
            console.log(this) // 这个是window. // 这玩意没啥用了 vue2所有的方法是可以都变成composition API 放到这里面的
            
            // jsx编写,需要借助babel jsx知道哪些是静态的哪些是动态的
            return h(
                'div',          
                {style:{color: 'red'},name:1, onClick: fn}, 
                `hello${arg.state.name}--${proxy.dlc}`         
            )
        
        }
        
        //=========================================
    }// 这就是入口
    
    // 在这里vue2的API还是可以用的比如data
    data(){ // optionsApi
        return {
            dlc: 'ding.luchao' // 这玩意用的是defineProperty 如何 用 vue3的reactivity 响应式API  compostionApi
        }
    },  
    
    methods: {
        say(){
            console.log(this); // this 这个上面的属性是哪里来的也不好判断vue2的。属性的类型也不好推断,所以不大好玩Ts【vue3 compostionApi 的可以自定义响应式数据,坏处就是组合起来麻烦】 这种API的好处是可以进行组合,vue2为了实现一个功能可能要分开写,组合式API可以组合在一起写。
        }//vue2是没有办法treeshaking的因为这个方法在这个对象里面也不知道用没用到,原因就是这个对象不知道哪个属性被用到了。
        
        
    },
    
    
    render(arg) { // 这个render和vue2的render是一样的,参数啥的不太一样。 vue2 render(h) 这里放的是个h vue3不是的
        // 这里没办法用this,this是谁? 这里的this 变成了proxy变成了一个代理对象
        console.log(arg);   // 这里的这个arg是个什么内容?变成了proxy变成了一个代理对象
        console.log(arg === this) ? // true 当前的arg会返回一个proxy对象
        // 这个proxy能获取什么?
        console.log(arg.dlc) // 可以拿到上面data定义的内容 当前arg会代理当前AppRoot上的一些数据
        // 这里的响应式API怎么用?
        return h(
            'div',          // 标签是div
            {style:{color: 'red'},name:1}, // 内容颜色是红色 name 是属性 前面的是样式
            `hello${arg.state.name}--${arg.dlc}`         // 内容是hello
        ) // 用h渲染一个标签, vue2的时候这个h方法写的会奔复杂
        
    }
    
}


// 创建应用
createApp(
    AppRoot,
    // 以哪个组件为入口
    {name: 'xbs'} // 上面setup的pros就可以拿到name 但是是个undefined为什么? 需要用 props声明一下
    // props
).mount("挂在到什么位置#app")
</script>