Vue3中props的原理与使用

简介: Vue3中props的原理与使用

前言

props指父组件往子组件中传入参数,我们来介绍下如何理解vue3的props的原理



介绍

了解其原理之前我们要清楚vue的虚拟节点是什么,有什么表现。


虚拟节点主要分成两种,分别是组件类型及元素类型,当然还有文本类型等特殊的虚拟节点。

虚拟节点都会接收三个基本参数,分别是type, props, children

对于组件类型而言:

{
  render() {
    return h() // render函数返回一个虚拟节点
  }
  setup() {}
}

props是父组件往子组件传入的参数


children是父组件往子组件传入的插槽


对于元素类型而言:


type是当前节点的元素类型,如div

props是当前节点的元素属性,如class

children是当前节点的子元素是个数组,数组的内容有可能是组件也有可能是元素


原理

前提

基于此我们可以创建两个组件互为父子的组件分别是APP组件(父),FOO组件(子)

import { h } from '../h.js';
import { Foo } from './foo.js';
export const App = {
    // render 页面元素内容即template
    render() {
        // 接收一个Foo,并通过h函数创建一个子组件node2
        let node2 = h(
            Foo,
            { 
              count: 1 
            },
            {}
        )
        return h(
            'div',
            {
                id: 'root',
            },
            [
                node2 // App接收Foo组件作为其子组件
            ] 
        );
    },
    setup() {
    }
};
import { h } from '../h.js';
// 定义一个Foo组件用于验证Props功能
export const Foo = {
    // render 页面元素内容即template
    render() {
        // ui 页面内容
        const foo = h(
            'div',
            {},
            'Foo' + this.count
        );
        return h('div', {}, [foo]);
    },
    // 第一个参数props,用于父子组件传值
    setup(props) { 
        console.log(props.count); // 打印传入的props值
    }
};

通过上面的代码我们可以看到,这里创建了两个文件分别代表父组件和子组件。

vue3的编译过程中我们会先去解析组件,就将组件传入patch函数中,判断当前的虚拟节点类型是组件还是元素,再走下面的编译。


上面的父组件代码中我可以看到对于Foo,我们创建了一个组件叫node2,并在props的位置中传入了一个count: 1的props。

let node2 = h(
    Foo,
    { 
      count: 1 
    },
    {}
)

因为我们创建vnode的时候,实际上会接收接收三个基本参数,分别是type, props, children


所以这里传入的vnode会带有props字段,而这个props字段是count:1(细品)


假设我们在这一步创建了一个组件实例对象,叫instance



初始化Props操作

因为instance就接收了vnode,而组件的vnode实际上包含了props


所以接着就会执行一个initProps的操作,如果vnode中props存在,那么就将props挂载到instance下的props字段中


这时候组件实例对象就可以正常的拿到props的值了



创建proxy对象去获取Props

因为我们知道代码中我们可以通过this. 的方式去获取props的值,而且props已经被挂载到了组件实例对象中。


因此创建一个proxy对象(后续通过bind的方式将这个对象挂载到render函数等位置,this.的时候由props去映射到对应的props中)

instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers);
const PublicInstanceProxyHandlers = {
    get({ _: instance }, key) {
        const { setupState, props } = instance
        // 如果在传入的props中,则返回的对应的值 (props)
        if (hasOwn(props, key)) {
            return props[key]
        }
    }
}
props作为参数传入setup

因为我们知道vue3中在setup中没有this,但可以接收一个props,通过这个props去获取到父组件传入的值。

那我们已经将props的值挂载到组件实例对象上,所以我们可以将props作为参数传入到setup中。

const {setup} = instance.type.setup // 获取setup函数
// 在执行setup的时候将props传入即可
setup(shallowReadonly(instance.props))


因此我们在使用的时候就可以通过接收props在setup中读值。

// 第一个参数props,用于父子组件传值
 
setup(props) {
 
    console.log(props.count); // 打印传入的props值
 
}

将proxy挂载到render上

在解析一个虚拟节点的时候,其实会先执行setup函数,然后再执行render,因为我们可以通过this. 的方式去获取props的值。


所以我们通过bind的方式将我们之前创建proxy对象挂载到render函数中,保证其this可以正确取到props的值。

instance.render.call(instance.proxy)


总结

到这里props的原理就讲完了。


props实际上是 父组件往子组件的虚拟节点的props处插入的参数。


因此我们在创建子组件的组件实例对象的时候可以拿到这个props的值并将其挂载到子组件的组件实例对象中。


如果组件中需要使用props,通常是两个位置setup或render


对于setup,我们可以将组件实例对象的props作为参数传入,这样就可以使用了,但是注意props是一个不能改的值,所以我们要用readonly包裹起来。


在组件的页面中我们可以通过 this. 的方式去读取props的值,所以在渲染页面即调用render函数的时候,我们可以通过创一个proxy对象,将这个对象挂载到render函数中,通过proxy去读取到对应的props值


相关文章
|
1天前
|
存储 JavaScript 开发者
Vue 3 组件通信方式总结
Vue 3 组件通信方式总结
|
1天前
|
存储 JavaScript API
Vue3基础(25)___初尝pinia,相比于vuex轻量、好用
本文介绍了Pinia在Vue 3中的使用,相比于Vuex,Pinia更轻量且易于使用。文章详细解释了Pinia的基本概念、优势,并提供了安装和使用Pinia的步骤,包括定义状态、getters、actions和如何在组件中使用Pinia进行状态管理。
14 3
Vue3基础(25)___初尝pinia,相比于vuex轻量、好用
|
1天前
|
JavaScript
在 Vue 3 组件通信方式中,Provide / Inject 与 Vuex 的区别是什么?
在 Vue 3 组件通信方式中,Provide / Inject 与 Vuex 的区别是什么?
|
1天前
|
存储 JavaScript
Vue 3 组件通信方式
Vue 3 组件通信方式
|
1天前
|
JavaScript 前端开发 API
Vue2与Vue3插槽使用的区别及案例
Vue 3在插槽功能上的改进,体现了其对开发体验的持续优化。通过简化API、加强动态特性和提升性能,Vue 3使得插槽的使用更加灵活和高效。这些改进不仅有助于减轻开发者的负担,还为组件之间的高级交互和内容复用打开了新的可能性。随着Vue生态系统的不断成熟,我们有理由相信,Vue将继续为前端开发提供强大且易用的工具。
10 3
|
1天前
|
JavaScript 前端开发 编译器
Vue3基础(26)___defineProps、defineEmits、defineExpose、defineModel组件通信、defineOptions
本文介绍了Vue 3中`<script setup>`语法糖的使用,以及如何在Vue 3的组合式API中使用`defineProps`、`defineEmits`、`defineExpose`和`defineModel`进行组件通信和属性暴露。同时,还解释了`defineOptions`的作用,它可以用来配置组件的选项,例如禁用属性的自动继承。
13 2
|
2天前
|
缓存 JavaScript API
vue3新一代状态管理库 Pinia
vue3新一代状态管理库 Pinia
12 1
|
2天前
如何在 Vue3 中创建一个计算属性?
如何在 Vue3 中创建一个计算属性?
9 1
|
2天前
|
缓存
Vue3 的 computed 和 watch 函数有哪些不同?
Vue3 的 computed 和 watch 函数有哪些不同?
在 Vue3 中,如何使用 setup 函数创建响应式数据?
在 Vue3 中,如何使用 setup 函数创建响应式数据?