微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

手把手教你写 Vue UI 组件库@vue2.0

手把手教你写 Vue UI 组件库

最近在研究 muse-ui 的实现,发现网上很少有关于 vue 插件具体实现的文章,官方的文档也只是一笔带过,对于新手来说并不算友好。

笔者结合官方文档,与自己的摸索总结,以最简单的 FlexBox 组件为例子,带大家入门 vue插件编写,如果您是大牛,不喜勿喷~

项目结构

| src
| ---| plugin
| ---| ---| flexBox                # 组件文件夹
| ---| ---| ---| flexBox.vue       # flex 布局的父组件
| ---| ---| ---| flexBoxItem.vue   # flex 布局的子组件
| ---| ---| ---| flexBox.scss      # 样式文件,我使用的是 sass
| ---| ---| ---| index.js          # 组件的出口
| ---| ---| styles                 # 公用的 css 样式文件
| ---| ---| index.js               # 插件的出口
| ---| App.vue
| ---| main.js

<一> 让项目装载插件

首先,我们不去理会组件的具体实现,先让我们的项目能够正常装载一个我们自定义插件

现在,我们的目标,是让项目能够正常显示这两个组件,能显示文本 flexBox demo 就可以啦!

./src/plugin/flexBox/flexBox.vue

<template>
  <div>flexBox demo</div>
</template>

<script>
export default {
    // 这是该组件的自定义名称,
    // 之后引用组件时就会用到这个名称。
    name: 'my-flexBox'
}
</script>

./src/plugin/flexBox/flexBoxItem.vue

<template>
    <div>flexBoxItem demo</div>
</template>

<script>
export default {
    name: 'my-flexBox-item'
}
</script>

./src/plugin/flexBox/index.js

这是整个 flexBox 组件的出口文件。\
因为这个组件有两个子组件,所以我们将引入的 default 改名为该组件的名称{ default as flexBox }

// 引用 scss 文件
import './flexBox.scss'  

// 引用组件
export { default as flexBox } from './flexBox.vue'
export { default as flexBoxItem } from './flexBoxItem.vue'

./src/plugin/index.js

现在,我们来到插件的出口文件

// ----- 1
import * as flexBox from './flexBox'

// ----- 2
const components = {
    ...flexBox
}

// ----- 3
const install = function (Vue, Option) {
    // ----- 4
     Object.keys(components).forEach((key) => {
        Vue.component(components[key].name, components[key])
    })
}

// ----- 5
export default {
    install
}
  1. 引入组件

  2. 定义 components 变量

  3. 这里是重点,vue 为编写插件提供了一个 install(Vue, Option) 方法,该方法为 vue 添加全局功能

    方法有两个参数,第一个Vue构造器,第二个是可选的参数;

  4. 使用 vue 的全局方法 Vue.component(Name, Object) 定义组件,第一个参数是组件名,第二参数是组件对象;

  5. 最后将组件认导出。

./src/main.js

我们来到 main.js在这里,我们将进行插件的最后配置啦。

使用 vue 的全局方法 Vue.use(PluginName, Options),第一个参数是插件的名字,第二个是可选的参数。

import plugin from './plugin'
Vue.use(plugin)

./src/App.vue

终于,我们可以在项目中引用我们定义的组件啦!

<template>
    <my-flexBox></my-flexBox>
    <my-flexBox-item></my-flexBox-item>
</template>

<二> FlexBox 组件的实现

组件的具体实现,就和平时自己写组件的方法是一样的了。

这里先贴出代码,我会将具体原理写在代码注释里面。

./src/plugin/flexBox/flexBox.vue

<template>
    <!-- 为组件绑定一个类,这个类的值通过计算属性来得出 -->
    <div class="my-flexBox"
         :class="classObj">
        <!-- slot 用来装载子组件,my-flexBox-item -->
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'my-flexBox',
    props: {
        // 子组件 my-flexBox-item 之间是否存在间隙,
        // 认,8px 的间隙。
        gutter: {
            type: Number,
            default: 8
        },
        // 子组件的排列方式,水平,或垂直排列。
        orient: {
            type: String,
            default: 'horizontal'
        },
        justify: {
            type: String
        },
        align: {
            type: String
        },
        wrap: {
            type: String,
            default: 'Nowrap'
        }
    },
    computed: {
        // 我们通过父级传递过来的参数,
        // 来判断该组件需要应用哪些样式
        // 如:<my-flexBox orient="vertical" justify="flex-start"></my-flexBox>
        classObj () {
            let classObj = {};

            // orient
            if (this.orient === 'vertical') classObj['flex-vertical'] = true;

            // wrap
            if (this.wrap === 'wrap') {
                classObj['flex-wrap'] = true
            } else {
                classObj['flex-Nowrap'] = true
            }

            // justify
            switch (this.justify) {
                case 'flex-start':
                    classObj['justify-start'] = true;
                    break;
                case 'flex-end':
                    classObj['justify-end'] = true;
                    break;
                case 'center':
                    classObj['justify-center'] = true;
                    break;
                case 'space-between':
                    classObj['justify-space-between'] = true;
                    break;
                case 'space-around':
                    classObj['justify-space-around'] = true;
                    break
            };

            // align
            switch (this.align) {
                case 'flex-start':
                    classObj['align-start'] = true;
                    break;
                case 'flex-end':
                    classObj['align-end'] = true;
                    break;
                case 'center':
                    classObj['align-center'] = true;
                    break;
                case 'baseline':
                    classObj['align-baseline'] = true;
                    break;
                case 'stretch':
                    classObj['align-stretch'] = true;
                    break;
            };

            return classObj;
        }
    }
}
</script>

./src/plugin/flexBox/flexBox.scss

scss 中定义需要使用到的样式

.my-flexBox {
    width: 100%;
    display: flex;
}
.flex-vertical {
    flex-direction: column;
}
.flex-wrap {
    flex-wrap: wrap;
}
.flex-Nowrap {
    flex-wrap: Nowrap;
}

/* justify */
.justify-start {
    justify-content: flex-start
}
.justify-end {
    justify-content: flex-end
}
.justify-center {
    justify-content: center
}
.justify-space-between {
    justify-content: space-between
}
.justify-space-around {
    justify-content: space-around
}

/* align */
.align-start {
    align-items: flex-start
}
.align-end {
    align-items: flex-end
}
.align-center {
    align-items: center
}
.align-baseline {
    align-items: baseline
}
.align-stretch {
    align-items: stretch
}

./src/App.vue

好了!我们可以在项目中用到这个组件了!

<template>
    <div id="app">
        <my-flexBox>
            <p>demo</p>
            <p>demo</p>
        </my-flexBox>
    </div>
</template>

你也可以让他们垂直排列!

<template>
    <div id="app">
        <my-flexBox orient="vertical">
            <p>demo</p>
            <p>demo</p>
        </my-flexBox>
    </div>
</template>

<三> FlexBoxItem 组件的实现

flexBox-item 组件和 flexBox 组件实现原理大同小异,直接贴代码了!

./src/plugin/flexBox/flexBox.vue

<template>
    <div class="my-flexBox-item"
         :style="styleObj">
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'my-flexBox-item',
    props: {
        grow: {
            type: [String, Number],
            default: 0
        },
        shrink: {
            type: [String, Number],
            default: 1
        },
        basis: {
            type: [String, Number],
            default: 'auto'
        },
        order: {
            type: [String, Number],
            default: 0
        }
    },
    computed: {
        styleObj () {
            let styleObj = {};

            // gutter
            let gutter = this.$parent.gutter,
                orient = this.$parent.orient;
            
            let marginName = orient === 'horizontal'?'marginLeft':'marginTop';
            styleObj[marginName] = gutter + 'px';

            // grow
            styleObj['flex-grow'] = this.grow;

            // shrink
            styleObj['flex-shrink'] = this.shrink;

            // basis
            styleObj['flex-basis'] = this.basis;

            // order
            styleObj['order'] = this.order;

            return styleObj;
        }
    }
}
</script>

./src/App.vue

<template>
    <div id="app">
        <my-flexBox>
            <my-flexBox-item grow="1">
                demo
            </my-flexBox-item>
            <my-flexBox-item>
                demo
            </my-flexBox-item>
        </my-flexBox>
    </div>
</template>

总结

这只是 vue 中编写插件的其中一个方法,还有更多的,例如:

  1. 使用 Vue.directive(Name, [Define])自定义指令,添加全局资源,如 vue-touch可以看我总结的这篇文章

  2. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

  3. 添加全局方法或者属性,如: vue-element

  4. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如 vue-router

本文的案例,只讲解了最简单的如何配置插件,意在帮助大家尽快上手。

觉得有帮助,就打赏打赏吧。

img

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐