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)
}
相关推荐
一点一木3 小时前
深度体验TRAE SOLO移动端7天:作为独立开发者,我把工作流揣进了兜里
前端·人工智能·trae
天外飞雨道沧桑4 小时前
TypeScript 中 omit 和 record 用法
前端·javascript·typescript
Lee川4 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
canonical_entropy5 小时前
从 Spec-Driven Development 到 Attractor-Guided Engineering
前端·aigc·ai编程
研☆香5 小时前
聊聊前端页面的三种长度单位
前端
给钱,谢谢!6 小时前
React + PixiJS 实现果园成长页:从状态机到浇水动画
前端·react.js·前端框架
暗冰ཏོ7 小时前
VUE面试题大全
前端·javascript·vue.js·面试
次元工程师!7 小时前
LangFlow开发(三)—Bundles组件架构设计(3W+字详细讲解)
java·前端·python·低代码·langflow
Bug-制造者8 小时前
现代Web应用全栈开发:从架构设计到部署落地实战
前端
青春喂了后端8 小时前
IntelliGit 前端状态层重构:把一个全局 Store 拆成清晰的状态边界
前端·重构·状态模式