vue函数式组件
什么是函数式组件?
我们可以把函数式组件想象成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML
对于函数式组件,可以这样定义:
- Stateless(无状态):组件自身是没有状态的
- Instanceless(无实例):组件自身没有实例,也就没有this
由于函数式徐建拥有拥有这两个特性,我们就可以把它用作高阶组件(High order components),所谓高阶,就是可以生成其他组件的组件。
函数式组件的特点
没有管理任何状态
没有监听任何传递给它的状态
没有生命周期方法
只接收一些prop的函数
函数式组件的优点
渲染开销低,因为函数式组件只是函数
为什么要使用函数式组件
速度快
因为函数式组件没有状态,所以我们不需要像vue的响应式 系统一样需要经过额外的 初始化。
函数式组件任然会对响应的变化 做出响应式变化,比如新传入props,但是在组件本身中,它无法知道数据什么时候发生变化,因为它不维护自身状态。
对于大型应用程序,在使用函数式组件之后,你会看到DOM的渲染和更新会有很大的改进。
函数式组件的适用场景
函数式组件可能不适用很多情况。因为使用JavaScript框架的目的是构建响应式的应用程序
适用场景:
- 一个简单的展示组件,也就是所谓的dumb组件,例如button组件,pills,tags,cards,甚至整个页面都是静态文本,比如about页面
- “高阶组件”用于接收一个组件作为参数,返回一个被包装过的组件
- v-for循环中每项通常都是很好的候选项。
functional:true加上render function,就是一个简单的函数式组件了
demo:
创建一个functionButton.js的函数式组件:
1 export default { 2 name: 'functional-button', 3 functional: true, 4 render(createElement, context) { 5 return createElement('button', 'click me') 6 } 7 }
函数式组件没有this,参数就靠context来传递
context的属性:
- props
- children
- slots(a slots object)
- parent
- listeners
- injections
- data
其中上面的data包含了其他属性的引用,nibility。
现在创建一个App.vue来引入上面的函数式组件
1 <template> 2 <FunctionalButton> 3 click me 4 </FunctionButton> 5 </template>
上面的click me就是FunctionButton.js的children属性,我们可以把组件改造下,有App.vue来定义组件的button按钮
1 export default { 2 name: 'funtional-button', 3 functional: true, 4 render(createElement, { children }) { 5 return createElement('button', children) 6 } 7 }
上面用了ES6参数的解构,用{children}来代替context
事件定义
函数式组件没有实例,事件只由父组件传递。下面在app.vue上定义一个最简单的click事件。
1 <template> 2 <FunctionalButton @click="log"> 3 Click me 4 </FunctionalButton> 5 </template>
对应的functionButton.js
1 export default { 2 functional: true, 3 render(createElement, { props, listeners, children }) { 4 return createElement( 5 'button', 6 { 7 attrs: props, 8 on: { 9 click: listeners.click 10 } 11 }, 12 children 13 ); 14 } 15 }
简单写法
vue中设计的api比较人性化,我们可以将props、listeners统一集中在data中。
1 export default { 2 functional: true, 3 render(createElement, { data, children }) { 4 return createElement( 'button', data, children ); 5 } 6 }
1 createElement('button', data, ['hello', ...children])
自己测试代码:
页面:
打印出来的数据
父通过v-bind传给子组件的,基本数据类型能在props中拿到,但是复杂数据类型Array,Object,Function就会在data中的attrs中拿到
父通过v-on传给子组件的事件能在render中context中data.on和listeners中拿到并通过元素的on+事件可以触发
贴上代码
parent.vue
1 <template> 2 <div> 3 <Child 4 v-bind="{ 5 name, 6 age, 7 sex, 8 infos, 9 infos5, 10 obj: { name: 'jackals', age: 32 }, 11 arr: [1, 2, 3] 12 }" 13 v-on="{infos2, infos3, infos4}" 14 /> 15 </div> 16 </template> 17 18 <script> 19 import Child from 'components/exersize1/Child' 20 export default { 21 components: { 22 Child 23 }, 24 data() { 25 return { 26 name: 'jackal', 27 age: 20, 28 sex: 'man' 29 } 30 }, 31 methods: { 32 infos() { 33 console.log('print', this.name, this.age) 34 }, 35 infos2() { 36 console.log('infos2') 37 }, 38 infos3() { 39 console.log('infos3') 40 }, 41 infos4() { 42 console.log('infos4') 43 }, 44 infos5() { 45 console.log('infos5') 46 } 47 } 48 } 49 </script> 50 51 <style> 52 </style>
child.vue
1 <script> 2 export default { 3 name: 'TextChild', 4 functional: true, 5 props: { 6 name: { 7 type: String, 8 default: '' 9 }, 10 age: { 11 type: Number 12 }, 13 sex: { 14 type: String, 15 default: '' 16 } 17 }, 18 render(h, context) { 19 const { props: { name, age, sex }, data: { attrs: { infos }, on: { infos2, infos3, infos4 }}} = context 20 console.log('conteext', context) 21 return ( 22 <div> 23 <div> 24 <p onClick={infos}>name: { name }</p> 25 <p>age: { age }</p> 26 <p>sex: { sex }</p> 27 </div> 28 <div> 29 <p onClick={infos2}>测试1:infos2</p> 30 <p onClick={infos3}>测试2:infos3</p> 31 <p onClick={infos4}>测试3:infos4</p> 32 </div> 33 </div> 34 ) 35 } 36 } 37 </script>
部分来自https://blog.csdn.net/time141/article/details/121927589