vue高级使用

  • 自定义组件
  • 1. 属性 prop
  • 2. 插槽 slot
  • 3. 自定义事件 event
  • 4. 组件的通讯
  • 对象和数组的动态更新
  • 自定义UI库( 模仿 element-ui)
  • 1、前置知识
  • 2、搭建目录
  • 3、编写组件
  • 4、暴露组件
  • 5、组件测试
  • 6、库模式打包
  • 7、发布到npm
  • Vue-cli
  • 1. 安装vue-cli
  • 2. 创建vue项目
  • 参考文献


自定义组件

组件及标签,我们可以对标签进行的设计有:

  • 标签中的属性(prop,就是使用标签时注入的值)
  • 标签中的内容(slot,标签填写的东西,也可以是其他标签)
  • 标签中的事件(event,使用 this.$emit(‘on-click’, event)指定使用标签时触发的事件)

一个再复杂的组件,都是由三部分组成的:prop、event、slot,它们构成了 Vue.js 组件的 API。如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后面再修改 API 就很困难了,使用者都是希望不断新增功能,修复 bug,而不是经常变更接口。

1. 属性 prop
<template>
  <button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>
<script>
    // 判断参数是否是其中之一
    function oneOf (value, validList) {
        for (let i = 0; i < validList.length; i++) {
            if (value === validList[i]) {
                return true;
            }
        }
        return false;
  }
 
  exportdefault {
    props: {
      size: {
        validator (value) {
          return oneOf(value, ['small', 'large', 'default']);
        },
        default: 'default'
      },
      disabled: {
        type: Boolean,
        default: false
      }
    }
  }
</script>

使用组件

<i-button size="large"></i-button>
<i-button disabled></i-button>

组件里定义的 props,都是单向数据流,也就是只能通过父级修改,组件自己不能修改 props 的值,只能修改定义在 data 里的数据,非要修改,也是通过后面介绍的自定义事件通知父级,由父级来修改。

在使用组件时,也可以传入一些标准的 html 特性,比如 id、class:

<i-button id="btn1"class="btn-submit"></i-button>

这样的 html 特性,在组件内的 元素上会继承,并不需要在 props 里再定义一遍。这个特性是默认支持的,如果不期望开启,在组件选项里配置 inheritAttrs: false 就可以禁用了。

2. 插槽 slot
3. 自定义事件 event
<template>
  <button @click="handleClick">
    <slot></slot
  </button>
</template>
<script>
export default {
    methods: {
      handleClick (event) {
        this.$emit('on-click', event);
      }
    }
  }
</script>

使用

<i-button @on-click="handleClick"></i-button>

上面的 click 事件,是在组件内部的 元素上声明的,这里还有另一种方法,直接在父级声明,但为了区分原生事件和自定义事件,要用到事件修饰符 .native,所以上面的示例也可以这样写:

<i-button @click.native="handleClick"></i-button>

如果不写 .native 修饰符,那上面的 @click 就是自定义事件 click,而非原生事件 click

4. 组件的通讯

yarn编译启动vue项目_UI

A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)。组件间经常会通信,Vue.js 内置的通信手段一般有两种:

  • $ref:给元素或组件注册引用信息;

$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

  • $parent / $children:访问父 / 子实例。

节制地使用 $parent$children - 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信

  • provide / inject:可以跨级通讯, 祖先组件 指定 provide ,其所有的子孙后代使用inject就可以获取provide中的内容

provideinject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

对象和数组的动态更新

//对象
_self.$set(_self.rowValue,'dealQuotaType',value)
_self.tableDataRequestParams = Object.assign({}, _self.tableDataRequestParams, {detailDMO: {mainConfId: _self.rowValue.id}})

//数组
_self.tableHeadDatas.splice(0, 1, TableHeadData.createDefaultNoShow({mainConfId: _self.rowValue.id}))

自定义UI库( 模仿 element-ui)

基于基于 vue-cli3 打造属于自己的 UI 库

1、前置知识
import Loading from '../components/loading'
// 方法一:name 是组件的名字
Vue.component(Loading.name, Loading)
// 方法二:前提是 Loading组件 有提供 install 这个方法
Vue.use(Loading);
2、搭建目录
  1. 添加配置文件
  2. 修改目录结构
  1. 把 src 目录名字改成 examples,这是用于展示组件示例的
  2. 在根目录下新建一个 packages 文件夹,这是用来放组件的
  3. yarn编译启动vue项目_UI_02

  1. 添加配置文件
    小改了一下目录之后,你会惊奇的发现项目运行不了了。没关系,这很正常,毕竟 src 都不见了,路径啥的肯定得报错。所以现在我们来解决这个问题。 在根目录下新建一个 vue.config.js 文件(新项目是没有这个文件的),并写入以下内容:
const path = require('path')
module.exports = {
  // 修改 pages 入口
  pages: {
    index: {
      entry: 'examples/main.js', // 入口
      template: 'public/index.html', // 模板
      filename: 'index.html' // 输出文件
    }
  },
  // 扩展 webpack 配置
  chainWebpack: config => {
    // @ 默认指向 src 目录,这里要改成 examples
    // 另外也可以新增一个 ~ 指向 packages
    config.resolve.alias
      .set('@', path.resolve('examples'))
      .set('~', path.resolve('packages'))

    // 把 packages 和 examples 加入编译,因为新增的文件默认是不被 webpack 处理的
    config.module
      .rule('js')
      .include.add(/packages/).end()
      .include.add(/examples/).end()
      .use('babel')
      .loader('babel-loader')
      .tap(options => {
        // 修改它的选项...
        return options
      })
  }
}
3、编写组件

一个组件库没有组件怎么行呢,所以我们要先写个 test 组件(你可以随便写,这不重要)。ok👌,我们先在 packages 目录下新建一个 test 文件夹,再在 test 文件夹下下面新建一个 src 文件夹,在 src 文件夹下面新建一个 test.vue 组件,大概长下面这样子👇:

yarn编译启动vue项目_UI_03

<!--test.vue-->
<template>
  <div class="xr-test" @click="handleClick">{{ num }}</div>
</template>

<script>
export default {
  name: 'XrTest', // 这个名字很重要,它就是未来的标签名<xr-test></xr-test>,坑了我一下
  data () {
    return {
      num: 0
    }
  },
  methods: {
    handleClick () {
      this.num++
    }
  }
}
</script>

<style lang="scss" scoped>
.xr-test {
  width: 100px;
  height: 100px;
  line-height: 100px;
  border-radius: 50%;
  font-size: 30px;
  text-align: center;
  background: #24292e;
  color: white;
}
</style>

⚠️这里主要强调一点,就是 name 这个名字尤为重要,我就在这个坑里呆了挺久。首先它是必须要写的,为啥呢,你可以把它理解为 id,具有唯一标识组件的作用,将来我们可是要通过这个 name 来找到和判定这是什么组件,所以你写的所有组件应该是不重名的;其次这个 name 就是我们最终的标签名,比如这里我们的 name 是 XrTest,到时候我们写的标签就长这样 ,就像 Element 一样,name 是 `ElButton`,用的时候就是

4、暴露组件

让我们在 packages/test 下面新建一个 index.js 文件,具体代码如下:

// 为组件提供 install 方法,供组件对外按需引入
import XrTest from './src/test'
XrTest.install = Vue => {
  Vue.component(XrTest.name, XrTest)
}
export default XrTest

这步的精髓就在于给组件扩展一个 install 方法,至于为什么要扩展这个方法,文章开头已经说到了,是因为 Vue.use() 的需要,use 会默认调用 install 方法安装,仅此而已。接着我们在 packages 下面也新建一个 index.js 文件,注意和上面那个 index.js 区别开,上面那个是针对单个组件安装的,这个是针对所有组件全局安装的,先看代码:

import XrTest from './test'
// 所有组件列表
const components = [
  XrTest
]
// 定义 install 方法,接收 Vue 作为参数
const install = function (Vue) {
  // 判断是否安装,安装过就不继续往下执行
  if (install.installed) return
  install.installed = true
  // 遍历注册所有组件
  components.map(component => Vue.component(component.name, component))
  // 下面这个写法也可以
  // components.map(component => Vue.use(component))
}

// 检测到 Vue 才执行,毕竟我们是基于 Vue 的
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

export default {
  install,
  // 所有组件,必须具有 install,才能使用 Vue.use()
  ...components
}

这步的主要作用就是统一导出所有组件及暴露 install 方法。之前的 index.js 只是安装单个组件,而现在这个 index.js 是循环安装所有组件,具体使用就看你是不是要按需引用了。这里给个目录结构方便大家观看:

yarn编译启动vue项目_UI_04

当然你可能会问道,为什么这样建目录?还能什么原因,因为 Element 是这样(如下图),所以我们这样写,仅此而已。

yarn编译启动vue项目_UI_05

5、组件测试

ok,组件写完了,接下来我们就在 examples 下面测试一下,看看能不能引用成功。 首先在 examples 下的 main.js 中引入刚刚写好的包,就像下面这样:

yarn编译启动vue项目_Vue_06

然后把 examples/views 下面的 Home.vue 里面的内容删了,写入自己标签组件,就像下面这样:

yarn编译启动vue项目_Vue_07

好了,最后让我们运行一下项目 npm run serve,看看效果,嗯,还凑合吧。

6、库模式打包

在 vue-cli3 中我们通过以下命令可以将一个单独的入口打包成一个库:

// target: 默认为构建应用,改为 lib 即可启用构建库模式
// name: 输出文件名
// dest: 输出目录,默认为 dist,这里我们改为 lib
// entry: 入口文件路径
vue-cli-service build --target lib --name lib [entry]

要注意的是在库模式中,打包出来的库中是不包含 Vue 的。 然后我们修改一下 package.json 文件,就像下面这样:

yarn编译启动vue项目_自定义事件_08

接着执行 npm run lib 就能生成库啦,看看左侧的目录是不是多了个 lib 文件夹,那个就是我们要发布的东西。

yarn编译启动vue项目_Vue_09

yarn编译启动vue项目_yarn编译启动vue项目_10

补充下,lib 目录下面的 js 之所以有好几种,是因为有两种规范(common 和 umd)、是否压缩(min)和映射(map)的区别,暂且知道有这么回事就行,不用深究。

7、发布到npm

万事俱备,只欠发布。

  1. 完善一下 README.md 文档
  2. 修改一下 package.json 文件:
{ 
  "name": "xr-ui",
  "version": "0.3.0",
  "description": "基于 vue-cli3 的 UI 组件库",
  "main": "lib/xr-ui.umd.min.js",  // 这是 lib 目录下的其中一个
  "keywords": "xr-ui",
  "private": false,
  "license": "MIT"
}
  1. 在根目录下新建一个 .npmignore 文件,内容和 .gitignore 差不多:
# 这是复制 .gitignore 里面的
.DS_Store
node_modules
/dist

# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

# 以下是新增的
# 要忽略目录和指定文件
examples/
packages/
public/
vue.config.js
babel.config.js
*.map
*.html

最后执行 npm login 登入 npm社区 账号(https://www.npmjs.com/注册),再执行 npm publish 发布即可,就这么简单的两步就可以,过一会在 npm 上就能搜到了。当然前提是你有个 npm 账号,没有的话去注册一个吧,很 easy 的,然后还要搜下你的 npm 包名是否有人用,有的话就换一个。

Vue-cli

1. 安装vue-cli
  1. 如果有vue-cli 2.0 1.0 要先卸载
npm uninstall vue-cli -g 
# OR
yarn global remove vue-cli
  1. 安装vue-cli
npm install -g @vue/cli
# OR
yarn global add @vue/cli
  1. 查看是否安装成功vue-cli
vue --version
2. 创建vue项目
//vue create 项目名称
vue create vuecli3test
//OR
vue ui
  1. 第一步可以选择自定义模块,空格键可以选中可取消选中。选择手动配置(如果喜欢使用eslint(代码风格规范检查)可以选择默认)
  2. yarn编译启动vue项目_UI_11

  3. 键盘上下键即可切换,刚开始其实有两个选项,我之前曾经自定义过,所以有三个。

yarn编译启动vue项目_vue_12

  1. 下一步默认
  1. 是否保存模板(预设)

yarn编译启动vue项目_UI_13

  1. 创建完成
  2. yarn编译启动vue项目_自定义事件_14

  3. 启动
npm run serve
  1. 可以通过vue的GUI界面来管理自己的项目
vue ui

yarn编译启动vue项目_自定义事件_15

参考文献

  1. 尤水就下. 基于 vue-cli3 打造属于自己的 UI 库[DB/OL]., 2019-03-28
  2. liuhua_2323.prop、event、slot简介[DB/OL]., 2019-11-28