Vue High order component
高阶组件
你原本有一个组件,你可以通过另外一个组件进行包裹,这个新的组件既具有原来组件的功能,又可以添加自己的功能,这种方式成为高阶组件。
①案例:
// 基础组件,只负责把传入src属性显示到一个图片标签
const Avatar = {
props: ['src'],
template: `<img :src="src">`
}
Avatar
组件,它接收一个src
属性并显示到img
标签。这个组件非常简单,但是在使用的时候不是很方便,因为我们需要传递一个完整的图片地址给它。我们使用的时候,希望只传递用户的名字就可以显示头像图片,这种场景使用高阶组件实现是最合适的。
②实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<smart-avatar username="fireworks99"></smart-avatar>
</div>
</body>
<script>
// 该函数只是用来模拟网络请求
function fetchURL(username, cb) {
setTimeout(() => {
// hard coded, bonus: exercise: make it fetch from gravatar!
cb('https://avatars3.githubusercontent.com/u/6128107?v=4&s=200' + username)
}, 500)
}
// 基础组件,只负责把传入src属性显示到一个图片标签
const Avatar = {
props: ['src'],
template: `<img :src="src">`
}
function withAvatarURL(InnerComponent) {
return {
props: ['username'],
inheritAttrs: false, // 2.4 only
data() {
return { url: null }
},
created() {
fetchURL(this.username, url => {
this.url = url
})
},
render(h) {
return h(InnerComponent, {
// attrs: this.$attrs, // 2.4 only
props: {
src: this.url || 'http://via.placeholder.com/200x200'
}
})
}
}
}
const SmartAvatar = withAvatarURL(Avatar);
new Vue({
el: '#app',
components: { SmartAvatar }
})
</script>
</html>
withAvatarURL
函数接收一个内部组件,然后返回一个高阶函数,在这个例子中,内部组件就是Avatar
,然后我们可以接收一个用户名,再通过用户名查询用户头像URL显示到页面上。
this.$attrs
用于获取组件所有属性,这是2.4之后才支持的功能,上面代码我们把高阶组件设置的属性传递给原始组件(在这个项目中没有体现意义)。
vs mixin
在上面案例的场景中,其实用minxin也是可以实现的,但是使用高阶组件有以下优势:
- 重用性。因为minxin对原组件具有侵入性,这会导致原来组件的可重用性降低,而高阶组件不会,高阶组件对原组件只是一个调用关系,并没有修改原来组件任何内容。
- 可测试性。因为高阶组件只是一个嵌套关系,在组件测试的时候,可以单独的测试原始组件和高阶组件。
- 层级问题。高阶组件也有他的弊端,如果你高阶组件嵌套层级太深,会导致出错的时候调试困难的问题,所以到底使用高阶组件和minxin需要看实际场景。