目录
- h方法介绍
- createElement简介
- createElement、this.$slots、scopedSlots用法
- 完整代码下载
一、h方法介绍
如果你接触过 vue 一段时间了,那么你可能会遇到过rendering
方法在你的 app 文件中 -- 在最新版本的CLI
中它是一个默认值, 并且是在main.js
文件中:
new Vue({
render: h => h(App)
}).$mount('#app')
或者是,如果你使用了 render
方法 (函数),可能会使用 JSX:
Vue.component('jsx-example', {
render (h) {
return <div id="foo">bar</div>
}
})
或许你想知道,h 是用来干嘛的?它表示什么意思呢? h 代表的是 hyperscript 。它是 HTML 的一部分,表示的是 超文本标记语言:当我们正在处理一个脚本的时候,在虚拟 DOM 节点中去使用它进行替换已成为一种惯例。这个定义同时也被运用到其他的框架文档中。详情点击这里 Cycle.js。
在这个问题上,Evan 描述到:
Hyperscript 它本身表示的是 "生成 HTML 结构的脚本"
缩写为 h 是因为它更容易去输入。 他还在 Frontend Masters 上描述了这一点 他的高级 Vue 研讨会 。
真的,你可以认为它是 createElement
的缩写。 这将是一个长长的形式:
//使用createElement
render: function (createElement) {
return createElement(App);
}
//用 h 代替它
render: function (h) {
return h(App);
}
//ES6简写
render: h => h (App)
名称 hyperscript 可能会让某些人感到困惑,因为 hyperscript 实际上是 一个库的名字(这些日子没有更新 ),它实际上有一个 小的生态系统。 在这种情况下,我们不是在谈论那个特定的实现。
希望能为那些感到困惑的人解决问题!
二、createElement简介
h(createElement)函数有3个参数
render(h){return h(param1,{},param3)}
- param1可以是 String | Object | Function
- 第二个是数据对象。 我们在这里主要包括:props, attrs, dom props, class 和 style....
- param3代表子节点,可以是 String | Array
更深入的信息你可以在 Vue 指南 里找到。
三、createElement、this.$slots、scopedSlots用法
3.1 createElement有3个参数(接上),我们先看看简单的
h( ’ div‘ , {} , String) 和 h( ’ div‘ , {} , Array) 这两种情况
父组件Parent.vue
//Parent.vue
//...
<baseComponent @customize-click="handleCustClick" :test="100"/>
const baseComponent = () => import("./BaseComponent")
export default {
components: {
baseComponent
}
//...
}
子组件BaseComponent.vue
//BaseComponent.vue
<style scoped>
.box{ background: rgba(0, 0, 0, 0.5) }
.a{ color: blue; text-decoration: underline }
.p{ color: firebrick }
</style>
<script>
export default {
name: 'BaseComponent',
props: {
test: Number,
},
methods: {
handleClick () {
this.$emit('customize-click')
}
},
render(h){
return h('div',{
'class': { box: true },
style: { fontSize: '14px' }
},[
'我是字符串',
h('p',{ 'class': { p: true } },'我是p标签'),
h('a',{ 'class': { a: true } },'我是a标签呀'),
h('p',{ on: { click: this.handleClick } },'点我!!!')
])
}
}
</script>
3.2 在看点有难度的:使用 this.$slots、this.$scopedSlots.default 创建带slot的子组件
PS :vue中提到的slot有匿名插槽、具名插槽、作用域插槽,同时也需要注意废弃的API
前2个先不看了,来看看作用域插槽:
有时让插槽内容能够访问子组件中才有的数据是很有用的。
我觉得官网说的不太清楚,我理解实质就是在具名插槽的基础上加了一个data,把data放到组件中。看demo理解的更快
Page.vue父组件引入调用
//Page.vue
<template>
<child>
//废弃写法
<template slot-scope="user">{{user.data}}</template>
//2.6.0之后写法
<template v-slot="user">{{user.data}}</template>
</child>
</template>
//...
Child.vue子组件定义
//Child.vue
<template>
<div>
<slot :data="list" name="user">
<h6>具名slot</h6>
</slot>
</div>
</template>
<script>
export default {
data: function(){
return {
list: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
}
}
}
</script>
3.2.1 对作用域插槽有了基本了解,我们在看看this.$slots 和 this.$scopedSlots的使用
this.$slots
:
你可以通过
this.$slots
访问静态插槽的内容
//template版本
<template>
<div>
<slot></slot>
</div>
</template>
//render版本
render: function (h) {
return h('div', this.$slots.default)
}
this.$scopedSlots :
也可以通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数:
//template版本
<template>
<div>
<slot :text="message" name="name1"></slot>
</div>
</template>
//...
props: ['message'],
render: function (h) {
return h('div', [
this.$scopedSlots.name1({
text: this.message
})
])
}
//...
下面我们来看一个简单的例子,来实战一下
Parent.vue
//Parent.vue
<template>
<h1>slot使用</h1>
<SlotC :list="[1,2,3,4]">
<p>asdasdsa</p>
</SlotC>
<h1>slot-scope使用</h1>
<Scc>
<!-- 废弃写法 -->
<div slot-scope="props">{{ props.text }}</div>
<!-- 推荐写法 -->
<template v-slot:deff222="props">
<p>{{props.text}}</p>
</template>
<template v-slot:csgo="props">
<p>{{props.text}}</p>
</template>
</Scc>
</template>
SlotC.vue
<script>
export default {
props: ['list'],
render(h){
console.log('我是$slots ',this.$slots);
return h('div', [this.list.map(item=>'-'+item),this.$slots.default])
}
}
</script>
CcopedSlotsC.vue
<script>
export default {
data(){
return {
default:'default',
deff222:'deff222',
csgo:'csgo'
}
},
props: ['list'],
render(h){
console.log('我是this.$scopedSlots',this.$scopedSlots);
return h('div', [
this.$scopedSlots.default({
text: this.default
}),
this.$scopedSlots.deff222({
text: this.deff222
}),
this.$scopedSlots.csgo({
text: this.csgo
})
])
}
}
</script>
3.2.2 createElement 第一个参数有个Object(组件选项对象)、第二个参数有个scopedSlots,我们来看下。
Parent.vue
//Parent.vue
<baseComponent @customize-click="handleCustClick" :test="100"/>
//...
BaseComponent.vue
//BaseComponent.vue
<style scoped>
.box{ background: rgba(0, 0, 0, 0.5) }
.a{ color: blue; text-decoration: underline }
.p{ color: firebrick }
</style>
<script>
import hw from './HelloWorld.vue';
export default {
name: 'BaseComponent',
props: {
test: Number,
},
methods: {
handleClick () {
this.$emit('customize-click')
}
},
// 使用scopedSlots
render(h){
return h(hw,{
scopedSlots: {
'name-slot': props => h(
'ul',
props.text.map(item=> h('li',item))
)
}},[
h('p',123),h('p',666),h('p',999)
])
}
}
</script>
HelloWorld.vue
//HelloWorld.vue
<template>
<div>
<slot name='name-slot' :text='list'></slot>
<h1>我是HW</h1>
<slot name="header"/>
<slot/>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
data() {
return {
list: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
}
}
}
</script>
四 、代码地址: 点我、点我、点我
参考:
在 Vue 的 render 方法中 h 是什么意思?learnku.com