Skip to content

Commit 4572da7

Browse files
committed
feat: 新增组件Attribute继承
1 parent 89c7c98 commit 4572da7

File tree

7 files changed

+105
-8
lines changed

7 files changed

+105
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ explorations
77
TODOs.md
88
*.log
99
.idea
10+
*.cmd

git_batch.cmd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
git push origin feature_server_renderer:master
2+
git push origin feature_server_renderer:develop
3+
git push origin feature_server_renderer:feature
4+
git push origin feature_server_renderer:feature_server_renderer

packages/runtime-core/src/component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export interface ComponentInternalInstance {
8484
emit: Function, // 事件的触发
8585
exposed: Object, // 暴露的方法
8686
isMounted: boolean, // 是否被挂载完成
87+
inheritAttrs: boolean, //是否使得子元素继承attrs
8788
bm: Function[] | null,//beforeMounted
8889
m: Function[] | null,//mounted
8990
bu: Function[] | null,//beforeUpdate
@@ -104,6 +105,7 @@ export function createComponentInstance(vnode, parent) {
104105
attrs: {}, // 除了props中的属性 //没定义的叫attrs
105106
slots: {}, // 组件的插槽
106107
next: null,
108+
inheritAttrs: type.inheritAttrs, //是否让孩子节点继承attrs
107109
parent,
108110
data, //data响应式对象
109111
update: () => { },//当前实例的effectRunner

packages/runtime-core/src/componentEmits.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { camelize, toHandlerKey } from "@mini-vue3/shared"
77
* @param instance 组件实例
88
*/
99
export function emit(instance, event: string, ...args) {
10-
const props = instance.props
10+
const props = instance.vnode.props
1111

1212
//转换为指定格式on开头的驼峰命名
1313
const evenName = toHandlerKey(camelize(event))

packages/runtime-core/src/componentProps.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import { extend, isOn } from "@mini-vue3/shared"
99
* @param isSSR 是否是ssr环境
1010
*/
1111
export function initProps(instance, rawProps, isStateful, isSSR = false) {
12+
debugger
1213
instance.data = isSSR ? instance.data : reactive(instance.data)
1314
const { props, attrs } = resolveProps(instance.propsOptions, rawProps)
1415

1516
if (isStateful) {
1617
//如果当前是ssr环境不需要创建响应式数据,因为ssr渲染的只是一个快照不需要响应式
1718
instance.props = isSSR ? props : shallowReactive(props)
1819
} else {
19-
//当前的组件是无状态的,是一个函数式组件,直接props == attrs
20-
instance.props = attrs
20+
//函数式组件的参数处理
21+
if (!instance.type.props) {
22+
//如果函数式组件没有定义内部的props选项直接props == attrs
23+
instance.props = attrs;
24+
} else {
25+
//如果定义了 props = props
26+
instance.props = props;
27+
}
28+
2129
}
2230
instance.attrs = attrs
2331
}
@@ -51,8 +59,8 @@ export function resolveProps(propsOptions, rawProps) {
5159
if (rawProps) {
5260
for (const key in rawProps) {
5361
const value = rawProps[key]
54-
//事件、响应式对象赋值到props中
55-
if (options.includes(key) || isOn(key)) {
62+
//响应式对象赋值到props中
63+
if (options.includes(key)) {
5664
props[key] = value
5765
} else {
5866
attrs[key] = value

packages/runtime-core/src/componentRenderUtils.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { normalizeVNode } from './vnode';
2-
import { ShapeFlags } from '@mini-vue3/shared';
2+
import { isOn, ShapeFlags } from '@mini-vue3/shared';
3+
import { Data } from './component';
34

45
export function shouldUpdateComponent(preVNode, nextVNode) {
56
const { props: preProps } = preVNode
@@ -58,6 +59,7 @@ export function hasPropsChanged(preProps, nextProps) {
5859
*/
5960
export function renderComponentRoot(instance) {
6061
let result
62+
let fallthroughAttrs //继承的的attrs
6163
const {
6264
type: Component,
6365
vnode,
@@ -69,7 +71,8 @@ export function renderComponentRoot(instance) {
6971
ctx,
7072
attrs,
7173
emit,
72-
slots
74+
slots,
75+
inheritAttrs //是否使得子元素继承attrs
7376
} = instance
7477

7578
//如果是普通的状态组件
@@ -84,6 +87,9 @@ export function renderComponentRoot(instance) {
8487
data,
8588
ctx)
8689
)
90+
91+
//直接取attrs
92+
fallthroughAttrs = attrs
8793
} else {
8894
//函数式组件
8995
//返回的函数render
@@ -93,6 +99,32 @@ export function renderComponentRoot(instance) {
9399
render.length > 1 ?
94100
render(props, { attrs, slots, emit }) : render(props, null)
95101
)
102+
103+
//函数式组件,需要特殊处理,因为在initPros时options props
104+
fallthroughAttrs = Component.props ? attrs : getFunctionalFallthrough(attrs)
105+
}
106+
107+
108+
//如果组件选项设置了inheritAttrs!=false即允许属性继承
109+
if (fallthroughAttrs && inheritAttrs !== false) {
110+
//子节点合并attrs
111+
result.props = {
112+
...result.props,
113+
...fallthroughAttrs
114+
}
96115
}
116+
117+
118+
97119
return result
98-
}
120+
}
121+
122+
const getFunctionalFallthrough = (attrs: Data): Data | undefined => {
123+
let res: Data | undefined
124+
for (const key in attrs) {
125+
if (key === 'class' || key === 'style' || isOn(key)) {
126+
; (res || (res = {}))[key] = attrs[key]
127+
}
128+
}
129+
return res
130+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<title>组件参数继承</title>
9+
</head>
10+
<style>
11+
.test {
12+
background-color: aquamarine;
13+
}
14+
</style>
15+
16+
<body>
17+
<div id="app"></div>
18+
19+
<script src="../dist/vue.global.js"></script>
20+
<script src="http://unpkg.com/vue"></script>
21+
<script>
22+
// const { effect, reactive, ref, computed, watch, createApp, h, onMounted, proxyRefs, Fragment } = Vue
23+
const { effect, reactive, ref, computed, watch, createApp, h, onMounted, proxyRefs, Fragment, KeepAlive } = MiniVue3
24+
25+
26+
27+
const App = {
28+
name: 'APP',
29+
props: {
30+
foo: {
31+
type: String,
32+
default: 'foo2'
33+
}
34+
},
35+
setup(props, { emit }) {
36+
return () => h('div', { class: 'test', id: props.foo }, 'AAAA');
37+
}
38+
39+
};
40+
const App2 = (props, { emit }) => {
41+
console.log(props)
42+
return h('div', { class: 'test', id: props.foo }, 'AAAA');
43+
};
44+
45+
createApp(App2, { bar: 'bar', foo: 'foo', onClick: (val) => { console.log('我改变了') } }).mount('#app');
46+
47+
</script>
48+
</body>
49+
50+
</html>

0 commit comments

Comments
 (0)