avatar
fireworks99
keep hungry keep foolish

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也是可以实现的,但是使用高阶组件有以下优势:

  1. 重用性。因为minxin对原组件具有侵入性,这会导致原来组件的可重用性降低,而高阶组件不会,高阶组件对原组件只是一个调用关系,并没有修改原来组件任何内容。
  2. 可测试性。因为高阶组件只是一个嵌套关系,在组件测试的时候,可以单独的测试原始组件和高阶组件。
  3. 层级问题。高阶组件也有他的弊端,如果你高阶组件嵌套层级太深,会导致出错的时候调试困难的问题,所以到底使用高阶组件和minxin需要看实际场景。
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy