# Component 组件渲染

WARNING

name 表示为组件名,自定义组件名(非全局注册组件)不可重复,否则会以前一个注册的组件显示

createElement 参数,具体查看 vue 文档 (opens new window)

{
	// 组件标签名
	name: 'el-input',
	// 与 `v-bind:class` 的 API 相同,
	// 接受一个字符串、对象或字符串和对象组成的数组
	'class': {
		foo: true,
		bar: false
	},
	// 与 `v-bind:style` 的 API 相同,
	// 接受一个字符串、对象,或对象组成的数组
	style: {
		color: 'red',
		fontSize: '14px'
	},
	// 普通的 HTML attribute
	attrs: {
		id: 'foo'
	},
	// 组件 prop
	props: {
		myProp: 'bar'
	},
	// DOM property
	domProps: {
		innerHTML: 'baz'
	},
	// 事件监听器在 `on` 内,
	// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
	// 需要在处理函数中手动检查 keyCode。
	on: {
		click: this.clickHandler
	},
	// 仅用于组件,用于监听原生事件,而不是组件内部使用
	// `vm.$emit` 触发的事件。
	nativeOn: {
		click: this.nativeClickHandler
	},
	// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
	// 赋值,因为 Vue 已经自动为你进行了同步。
	directives: [
		{
		name: 'my-custom-directive',
		value: '2',
		expression: '1 + 1',
		arg: 'foo',
		modifiers: {
			bar: true
		}
		}
	],
	// 作用域插槽的格式为
	// { name: props => VNode | Array<VNode> }
	scopedSlots: {
		default: props => createElement('span', props.text)
	},
	// 如果组件是其它组件的子组件,需为插槽指定名称
	slot: 'name-of-slot',
	// 其它特殊顶层 property
	key: 'myKey',
	ref: 'myRef',
	// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
	// 那么 `$refs.myRef` 会变成一个数组。
	refInFor: true
}

# 渲染组件方式

该方式只用于渲染已注册的组件,不可添加 render 参数。

{
    label: '店铺类型',
    prop: 'type',
    value: 0,
	component: {
		// 任意组件名,el-button, el-input, cl-upload ...
		name: 'el-select',
		// 只有 name 为:el-select, el-radio-group, el-checkbox-group 可用,作为选项值
		options: [
            {
                label: '淘宝',
                value: 0
            },
            {
                label: '天猫',
                value: 1
            }
        ],
		// 带入参数
		props: {
            clearable: true
        },
		// 监听事件
		on: {
			change: (val) => {
                // 注意使用箭头函数
                console.log(val)
			}
		}
		...
	}
}

# 函数方式

h 为 createElement

scope 作为表单数据或者行数据

// buttons
{
	buttons: [
		({ h, scope }) => {
			return h(
				"el-button",
				{
					props: {
						type: "primary"
					}
				},
				"按钮名称"
			);
		}
	];
}

// component
{
	component: ({ h, scope }) => {
		return h("el-input", {
			props: {
				type: "textarea"
			},
			attrs: {
				placeholder: "请填写内容"
			}
		});
	};
}

# 自定义渲染

name 不可重复,也不可填写已注册的组件。例如 el-button 为不可填

const list = [
	{
		label: '淘宝',
		value: 0
	},
	{
		label: '天猫',
		value: 1
	}
]

{
	items: [
		{
			label: '店铺选择',
			prop: 'shopId',
			component: {
                // 唯一标识
				name: "shop-select",

				// 传入参数
				attrs: {
					list
				}

				props: {
					// 默认 value 为表单绑定 prop 对应的值
					value: null,
					list: null
				},

				data() {
					return {
						value2: null
					};
				},

				watch: {
					value: {
						immediate: true,
						handler(val) {
							this.value2 = val;
						}
					}
				},

				methods: {
					onChange(val) {
						this.$emit("input", val);
					}
				},

				render() {
					return (
						<el-select v-model={this.value2} on-change={this.onChange}>
							{
								this.list.map(e => {
									return (
										<el-option label={e.label} value={e.value}></el-option>
									)
								})
							}
						</el-select>
					);
				}
			}
		}
	]
}

# 组件实例方式

默认 value 为表单绑定 prop 对应的值

<!-- /src/components/search-coupon.vue -->
<template>
	<div class="search-coupon">
		{{ value }}
	</div>
</template>

<script>
	export default {
		props: {
			value: String
		}
	};
</script>
import SearchCoupon from "@/components/search-coupon";

{
	items: [
		{
			label: '搜索优惠券',
			prop: 'couponId',
			component: SearchCoupon;
		}
	]
}

# 插槽方式

对不熟悉 jsx 方式的同学,尽可能使用插槽,避免作用域等等问题~

提示

name 必须以 slot- 开头, 如 slot-name。插槽名称必须与 name 一致

cl-form, cl-upsert 下使用,scope 为表单绑定值

{
	label: '昵称',
	prop: 'name',
	component: {
		name: "slot-name";
	}
}
<cl-form>
	<!-- 加入插槽 -->
	<template #slot-name="{ scope }">
		<span>昵称:</span>
		<el-input v-model="scope.name"></el-input>
	</template>
</cl-form>

cl-table 下使用,scope 参数为 { row, column, $index }

{
	type: 'op',
	buttons: ['slot-btn']
}
<cl-table>
	<!-- 加入插槽 -->
	<template #slot-btn="{ scope }">
		<el-button @click="toDetail(scope.row.id)">查看详情</el-button>
	</template>
</cl-table>

# vue3 上的差异

  • 所有的参数都以 props 传递

  • 事件 on 遗弃,改用 onChange, onInput, on{事件名称,首字母大写} 方式。在 props 中有效

  • tsx 中,可以使用 render 返回 html 内容,使用 setup 返回 data 和 function

  • 绑定值:value -> modelValue

  • emit 需要添加 emits, 如:

export default defineComponent({
	props: {
		modelValue: String
	},
	emits: ["update:modelValue", "change"]
});
  • props 添加 function({ scope, isEdit }) 预处理,返回有效值