最近在研究 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

手把手教你写 Vue UI 组件库的更多相关文章

  1. 16款优秀的Vue UI组件库推荐

    16款优秀的Vue UI组件库推荐 Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基 ...

  2. 为公司架构一套高质量的 Vue UI 组件库

    有没有曾遇过,产品要我们实现一个功能,但是 iview 或者 elementui 不支持,我们然后义正言辞的说,不好意思,组件库不支持,没法做到. 有没有曾和设计师争论得面红耳赤,其实也是因为组件库暂 ...

  3. 强烈推荐优秀的Vue UI组件库

    Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基于Vue的UI组件框架开发,并投入正 ...

  4. 【转】优秀的Vue UI组件库

    原文来源:https://www.leixuesong.com/3342 Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司 ...

  5. Vue UI组件库

    1. iView UI组件库  iView官网:https://www.iviewui.com/ 2.Vux UI组件库   Vux官网:https://vux.li/ 3.Element UI组件库 ...

  6. 前端如何搭建vue UI组件库/封装插件(从零到有)

    需求 因之前是做外包项目居多,经常用到相同的组件,之前的办法是在一个项目中写一个组件,其他项目直接将compents下的组件复制,粘贴到项目中使用,缺点是维护起来,改一个项目,其他项目也需要修改,所以 ...

  7. 创建一个自己的Vue UI组件库,并将它发布在npm上

    本文仅限于入门级,没有成规模制作,希望能对你有所帮助. 因为在开发多个项目中可能会用到同一个组件,那么我们通过复制粘贴的形式更新,无异于是笨拙的,我们可以通过上传到npm后,不断迭代npm包来实现更新 ...

  8. 手把手教你写vue插件并发布(一)

    vue的插件开发 这篇文章较长,需要一定的阅读时间.这里有一份改善版本的插件笔记,在一个项目下完成开发.测试.发布的全过程.https://www.cnblogs.com/adouwt/p/96555 ...

  9. 仿写vue UI 组件总结 (自己练习,仿照现有的UI组件)

    UI组件 Vue开发插件流程 本来是昨天要写总结的,感觉自己写不好,就放弃了.今天看到了iview和element有一些摩擦,是关于代码借鉴的问题(哈哈),不做评价.谁下生会写组件,我仿(chao)写 ...

随机推荐

  1. TypeScript完全解读(26课时)_6.TypeScript完全解读-泛型

    6.TypeScript完全解读-泛型 创建实例ts文件generics.ts 在index.ts内引入 fill是填充数组,创建的数组的元素数是times,填充的值就是接收的value的值 这里传入 ...

  2. Swift 4.0 中的 open,public,internal,fileprivate,private

    1.private private访问级别所修饰的属性或者方法只能在当前类里访问. 2.fileprivate fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问. ...

  3. JavaScript代码风格和分号使用问题

    1.推荐代码风格 JavaScript Standard Style  规定相对松散更多人使用此规范 Airbnb JavaScript Style  规定更严格但也没毛病 2.JavaScript代 ...

  4. Weekly Contest 78-------->811. Subdomain Visit Count (split string with space and hash map)

    A website domain like "discuss.leetcode.com" consists of various subdomains. At the top le ...

  5. CentOS Linux 7 提示 lsof: 未找到命令

    我们常使用 lsof -i:端口号 命令来查看某端口是否开放,如使用下面的命令,查看8080端口: lsof -i: 结果: 提示:lsof:未找到命令 解决办法 使用yum来安装lsof,命令如下: ...

  6. unity3d 在UGUI中制作自适应调整大小的滚动布局控件

    http://blog.csdn.net/rcfalcon/article/details/43459387 在游戏中,我们很多地方需要用到scroll content的概念:我们需要一个容器,能够指 ...

  7. 阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:4. 设备上报属性

    文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...

  8. swift SqliteDB使用

    操作步骤: 1,在 Build Phases -> Link Binary With Libraries 中点击加号,添加 libsqlite3.0.tbd 到项目中来   2,创建连接头文件B ...

  9. WKWebView简单使用

    #import <WebKit/WebKit.h> @interface SchoolOverviewsViewController ()<WKUIDelegate,WKNaviga ...

  10. HDU-1556:Color the ball(前缀和)

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...