22-mini-vue props

实现组件 props 功能

  1. 功能
  • 通过 setup 函数传递 props 属性
  • 在模板中通过 this 访问 props 属性
  • 不可以修改 props 属性
  1. 思路
  • 在 mountElement 函数中拦截 props 属性
  • 将 props 属性通过 el.setAttribute 设置到元素上
  1. 代码实现
  • 页面上要实现的功能,创建完 Foo,引入就可以把 子组件不涉及 props 的文本渲染过来
js 复制代码
// exmaple/Foo.js  // ✅
import {h} from '../lib/guide-mini-vue.esm.js'
export const Foo = {
  render() {
    return h("div", {},"foo:" + this.count)
  },
  setup (props) {
    console.log(props.count,'count');
    return {
    }
  }
}
js 复制代码
// example/App.js
import { h } from '../lib/guide-mini-vue.esm.js'
import { Foo } from './Foo.js'

window.self = null
export const App = {
  name: 'App',
  render() { 
    window.self = this
    return h("div",{
      id: 'root',
      class: ['red', 'hard'],
    },
    [h("p",{class:"red"}, "hi"),h(Foo,{count: 1})]  // ✅
    )
  },
  setup() {
    return {
      msg: "mini-vue-haha",
    }
  }
}
  • 具体实现
js 复制代码
// runtime-core/component.ts
import { shallowReadonly } from "../reactivity/reactive"
import { initProps } from "./componentProps"
export function setupComponent(instance) {
  initProps(instance, instance.vnode.props) // ✅ 将props挂载到实例上
  setupStatefulComponents(instance)
}

function setupStatefulComponents(instance: any) {
  const Component = instance.vnode.type
  const { setup } = Component
  instance.proxy = new Proxy({_: instance}, PublicInstanceProxyHandlers)
  if(setup) {
    // ✅ 将props传递到 setup 函数, 此时控制台已经能够打印出 props的值 在 Foo.js 中
    // ✅ 这里的 shallowReadonly 做了容错处理,具体在下面
    const setupResult = setup(shallowReadonly(instance.props))  
    handleSetupResult(instance, setupResult) 
  }
}
js 复制代码
// runtime-core/componentProps.ts 
export function initProps(instance, rawProps) {
  instance.props = rawProps || {} // ✅ 这里是做了兼容性处理,如果不做,在获取 value 时,会因为 props 为空而报错,要知道不是每个组件都有给子组件传递 props 属性
}
js 复制代码
// runtime-core/ componentPublicInstance.ts
import { hasOwn } from "../shared/index" // ✅

const publicPropertiesMap = {
  $el:(i)=>i.vnode.el
}

export const PublicInstanceProxyHandlers = {
  get({_: instance}, key) {
    let { setupState, props } = instance
    if(hasOwn(setupState,key)) { 
      return setupState[key]
    } else if(hasOwn(props, key)) { // ✅ 判断访问的 key 是否在 props 上,如果在就返回属性值,此时页面已经可以渲染到 props
      return props[key] // ✅
    }
    const publicGetter = publicPropertiesMap[key]
    if(publicGetter) {
      return publicGetter(instance)
    }
  }
}
js 复制代码
// reactive/reactive.ts
function createReactiveObject(target, baseHandlers) {
  if(!isObject(target)) { // ✅ 这是 shallowReadonly 做的容错处理
    console.warn(`target ${target} 必须是一个对象`)
    return target
  }
  return new Proxy(target, baseHandlers)
}
js 复制代码
export const hasOwn = (val, key) => {  // ✅
  if(!val) {
    return false
  }
  return Object.prototype.hasOwnProperty.call(val, key)
}
相关推荐
optimistic_chen6 分钟前
【Vue3入门】vue-router 路由管理
前端·javascript·vue.js·路由·router
柯儿的天空21 分钟前
WebGPU全面解析:新一代Web图形与计算API
前端·chrome·microsoft·前端框架·chrome devtools·view design
捕捉一只前端小白24 分钟前
cpolar内网穿透以及微信小程序域名设置
前端·vue.js·微信小程序·小程序
wuhen_n28 分钟前
ESLint + Prettier + Husky + lint-staged:建立自动化的高效前端工作流
前端·javascript·vue.js
xiangpanf28 分钟前
PHP与Vue:前后端技术深度对比
开发语言·vue.js·php
小同志0028 分钟前
HTML 基础
前端·javascript·html
wuhen_n2 小时前
网络请求在Vite层的代理与Mock:告别跨域和后端依赖
前端·javascript·vue.js
小彭努力中2 小时前
193.Vue3 + OpenLayers 实战:圆孔相机模型推算卫星拍摄区域
vue.js·数码相机·vue·openlayers·geojson