组件中使用响应式方法,本节就介绍用法。
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>