函数式组件
在components文件夹中新建list.vue和index.js文件进行配置(新建一个组件)
<template>
<div>
<ul>
<li v-for="(item, index) in list" :key="`item_${index}`"></li>
</ul>
</div>
</template>
<script>
export default {
name: 'List',
props: {
list: {
type: Array,
//数组设置默认值时需要设置参数
default: () => []
}
}
}
</script>
import List from './list.vue'
export default List
在views中的render-page页面引入并注册
import List from '_c/list'
components: {
List
}
<template>
<div>
<list :list='list'></list>
</div>
</template>
如果追求个性化,不想用span标签包裹数据,则可以在父组件中(views中的render-page页面)传入自定义的render(我们在后面将其在子组件注册)
<template>
<div>
<list :list='list' :render='renderFunc'></list>
</div>
</template>
methods: {
renderFunc (h) {
return h('i', {
style: {
color: 'pink'
}
//这里传入第三个参数
}, )
}
}
接下来我们需要使用到函数式组件
函数式组件没有正常组件的钩子函数,生命周期,只是用来接收参数的函数
在components文件夹下定义render-dom.js文件用来配置函数式组件
export default {
// 设置为true,意味着这个组件没有状态和实例
// 引入到其他页面时vue会对其进行处理,将render函数里面的虚拟节点进行渲染
functional: true,
props: {
name: String,
renderFunc () {}
},
render: (h, ctx) => {
// h参数为渲染函数
// 第二个参数是一个实例,指代当前导出的对象
return ctx.props.renderFunc(h, ctx.props.name)
}
}
在子组件(list.vue)中配置函数式组件
<template>
<div>
<ul>
<li v-for="(item, index) in list" :key="`item_${index}`">
<!-- 如果用户没用使用自定义render -->
<span v-if='!render'>{{ item.name }}</span>
<!-- 这里我们将在render-dom.js定义的属性写成驼峰式 -->
<render-dom v-else :render-func='render' :name='item.name'></render-dom>
</li>
</ul>
</div>
</template>
<script>
import RenderDom from '_c/render-dom'
export default {
name: 'List',
components: {
RenderDom
},
props: {
list: {
type: Array,
default: () => []
},
render: {
type: Function,
default: () => {}
}
}
}
</script>
接下来在父组件(views中的render-page.vue)中进行配置
methods: {
// 第一个参数为渲染函数,第二个参数为render-dom的name
renderFunc (h, name) {
return h('i', {
style: {
color: 'pink'
}
}, name)
}
}
效果图
3.JSX
jsx是在js中写html标签还有特定的语法,最后把其转换成js并且用render渲染
下面我们使用jsx
在之前步骤的基础上,在render-page(父组件中)改动
methods: {
// 使用jsx这里必须使用h
// 在jsx中变量首先要用一个花括号包起来
// 花括号里是一个对象,对象里面也有一个花括号,然后定义属性
renderFunc (h, name) {
return (
<i style={{ color: 'red' }}>{name}</i>
)
}
}
3.1在jsx中如何给标签绑定事件
methods: {
renderFunc (h, name) {
return (
<i on-click={this.handleClick} style={{ color: 'red' }}>{name}</i>
)
},
handleClick (event) {
console.log(event)
}
}
3.2在jsx中如何渲染组件
首先在父组件(views中render-page)中引入组件(这里我们以countTo组件为例)
在render和jsx中使用组件不需要在components中注册
import CountTo from '_c/count-to'
将render-dom.js、list.vue、render-page.vue中的name全部改为num,同时将render-dom.js中的props属性下的name值由String换为Number
methods: {
renderFunc (h, number) {
return (
<CountTo endVal={number} on-click={this.handleClick} style={{ color: 'red' }}>{number}</CountTo>
)
},
handleClick (event) {
console.log(event)
}
}
3.3在jsx中如何给引用的组件绑定自定义事件和原生事件
绑定自定义事件
methods: {
renderFunc (h, name) {
return (
// 使用on绑定自定义事件
// 使用nativeOn绑定原生事件
// on-animation-end为我们在countTo组件中定义的事件
<CountTo nativeOn-click={this.handleClick} on-on-animation-end={this.handleEnd} endVal={name} style={{ color: 'red' }}>{name}</CountTo>
)
},
handleClick (event) {
console.log(event)
},
handleEnd () {
console.log('end!')
}
}
3.4在render和jsx中如何阻止鼠标选中
还有很多在template中的修饰符在render中使用不了的需要查阅文档
在子组件中进行配置
<li @mousemove="handleMove" v-for="(item, index) in list" :key="`item_${index}`">
调用事件对象的preventDefault方法阻止鼠标移动事件的默认行为
methods: {
handleMove (event) {
event.preventDefault()
}
}
4.作用域插槽
我们通过作用域插槽来实现自定义内容的渲染
在list.vue子组件中
<template>
<div>
<ul>
<li @mousemove="handleMove" v-for="(item, index) in list" :key="`item_${index}`">
<slot :number='item.number'></slot>
</li>
</ul>
</div>
</template>
在父组件中删去render属性,由于我们要在template中使用countTo组件,所以要在components中注册
<template>
<div>
<list :list='list' >
<!-- 使用slot-scope属性并且随便定一个名称值,这个名称是一个包含了子组件插槽中的属性以及值的对象-->
<count-to slot-scope="count" :end-val='count.number'></count-to>
</list>
</div>
</template>
components: {
List,
CountTo
}