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)
}
相关推荐
kyriewen118 分钟前
每日知识点:this 指向之谜——是谁在 call 我?
前端·javascript·vue.js·前端框架·ecmascript·jquery·html5
浩星9 分钟前
electron系列6之性能优化:从启动慢到内存泄漏
前端·javascript·electron
飞Link13 分钟前
pprint 全量技术手册:复杂数据结构的结构化输出引擎
开发语言·前端·python
前端那点事16 分钟前
Vue3 代码编写规范 | 避坑指南+团队协作标准
vue.js
Ruihong17 分钟前
Vue 迁移 React 实战:VuReact 一键自动化转换方案
前端·vue.js
opbr19 分钟前
还在手写 env 类型定义?这个 Vite 插件帮你自动搞定!
前端·vite
Qinana19 分钟前
前端正则表达式全解:从基础语法到实战应用
前端·javascript·面试
蜡台23 分钟前
JavaScript Object Function ERROR
开发语言·javascript·ecmascript·error
烟话625 分钟前
vue3响应式基础
前端·javascript·vue.js
boombb27 分钟前
用户反馈入口
前端