zoukankan      html  css  js  c++  java
  • 手把手教你写 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 {
         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

  • 相关阅读:
    [BUUCTF]REVERSE——rsa
    windows下python3.7安装gmpy2、Crypto 库及rsa
    [BUUCTF]PWN——wustctf2020_getshell1/2
    [BUUCTF]PWN——bbys_tu_2016
    [BUUCTF]PWN——xdctf2015_pwn200
    [BUUCTF]REVERSE——[GXYCTF2019]luck_guy
    [BUUCTF]REVERSE——简单注册器
    [BUUCTF]PWN——pwnable_orw
    [BUUCTF]REVERSE——findit
    [BUUCTF]PWN——jarvisoj_level1
  • 原文地址:https://www.cnblogs.com/chiangyibo/p/8441278.html
Copyright © 2011-2022 走看看