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)
}
相关推荐
REDcker15 小时前
显示分辨率标准对照详解
前端·网络·分辨率·显示·屏幕
এ慕ོ冬℘゜15 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
武子康15 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
随心点儿16 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
一点一木16 小时前
从60首歌到1个网站:输入你的故事,还你一首歌
前端·github
IT_陈寒17 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
kyriewen17 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
遇乐的果园18 小时前
前端学习笔记-vue加载渲染优化
前端·笔记·学习
用户9850335932818 小时前
OpenLayers 热力图从原理到 Vue 组件一键接入
前端
颜酱18 小时前
01 | 骨架搭建:FastAPI + Vue 跑通第一个 SSE 流式问答
前端·人工智能·后端