*.vue
文件;<template>
<div>
<h1>demoh1>
<h1> {{name}} h1>
<demoComp/>
div>
template>
<script>
import demoComp from './view/democomp'
export default {
name:'sub-menu',
components:{demoComp},
props: ['menuInfo'],
data:{
return:{
name:'haha'
}
},
methods:{
hello(){
console.log('hello')
}
},
created(){
}
}
script>
<style>
*{
margin: 0;
padding: 0;
}
style>
functional
单文件组件如此声明可以不用再js里增加functional:true
属性值
单文件组件声明方式:
<template functional>
<div>{{ props.foo }}div>
template>
旧声明方式:
Vue.component('smart-list', {
//标记为函数式组件
functional: true,
//render函数
render: function (createElement, context) {
//规定组件的渲染规则
function appropriateListComp() {
}
//生成模板
return createElement(
//模板标记为渲染规则函数返回值
},
props: {
items: {
type: Array,
required: true
},
isOrdered: Boolean
}
})
<template>
<democom/>
<template/>
export default{
name:'democom'
}
如果是函数式组件就不需要另外在name属性中声明了!
由于函数式组件都是在渲染函数上下文中进行求值,所以,不能通过data,不能通过this对数据进行访问,官方文档也做了详细的阐述:
组件需要的一切都是通过上下文传递,包括:
functional: true
之后,锚点标题组件的 render 函数之间简单更新增加 context 参数,this.$slots.default
更新为 context.children
,之后this.level 更新为 context.props.level
。因为函数式组件只是一个函数,所以渲染开销也低很多。然而,对持久化实例的缺乏也意味着函数式组件不会出现在 Vue devtools 的组件树里。
以我的一个例子来讲:例子来源于ant-design-vue的导航组件,很多大型单页项目里,导航会跟着用户的操作进行动态的变化,如果冗杂的手动书写导航菜单并用显隐控制显然是开销巨大的!那么根据设定好的数据进行递归渲染明显是一个可行的好办法!
组件地址
忽略我是用的pug语法,使用了一些事件方法,我们看重点:
首先,a-menu是ant的导航组件容器,子组件在a-menu下不能用其他盒子包裹,子组件包含两种:普通导航a-menu-item
和折叠导航 a-sub-menu
,我这里选择将折叠作为依据进行判断然后重复递归渲染:
.content
.leftnav
a-menu(
:defaultSelectedKeys="['1']"
:defaultOpenKeys="['2']"
:mode="'inline'"
:inlineCollapsed="collapsed"
@click="handleClick")
template(v-for="item in navigations")
a-menu-item(
v-if="!item.children"
:key="item.key")
a-icon(type="pie-chart")
span {{item.title}}
sub-menu(
v-else
:menu-info="item"
:key="item.key")
引入自定义函数式组件:
import SubMenu from '../components/subMenu'
components:{
cub-menu:SubMenu
}
<template lang='pug' functional>
a-sub-menu(
:key="props.menuInfo.key")
span(slot="title")
a-icon(type="mail")
span {{ props.menuInfo.title }}
template(v-for="item in props.menuInfo.children")
a-menu-item(
v-if="!item.children"
:key="item.key")
a-icon(type="pie-chart")
span {{ item.title }}
sub-menu(
v-else
:key="item.key"
:menu-info="item")
</template>
<script>
export default {
// name:'sub-menu',
props: ['menuInfo'],//遵守规范,html不适用大写字母,驼峰命名会被解析成短横线
}
</script>
看一下我的数据:
navigations: [{
key: '1',
title: 'Option 1',
},{
key: '2',
title: 'Navigation 2',
children: [{
key: '2.1',
title: 'Navigation 3',
children: [
{ key: '2.1.1',
title: 'Option 2.1.1',
},
]},
],
},{
key: '3',
title: 'Navigation 3',
children: [{
key: '3.1',
title: 'Navigation 4',
children: [
{ key: '3.1.1',
title: 'Option 3.1.1',
},
],
}],
}],
渲染出来的效果:
父组件通过v-bind:menu-info:"item"
想子组件传递了含有children的数据,子组件通过props接受,并赋值到menuInfo
中,数据通过props.menuInfo
调用,注意的是,vue的数据传递模板里使用短横线({{ props.menu-info.title }}
)是不行的,所以在props里使用menuInfo命名!虽然:menuInfo="item"
也不会报错,但是并不符合html的规范,不建议在html的标签里使用驼峰命名(组件会被js先解析之后再添加到DOM里渲染,故组件名是可以使用驼峰命名的)!