12

十分钟快速上手NutUI

 4 years ago
source link: https://segmentfault.com/a/1190000022704890
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文将会从 NutUI 初学者的使用入手,对 NutUI 做了一个快速的概述,希望能帮助新人在项目中快速上手。

文章包括以下主要内容

  • 安装引入 NutUI
  • NutUI 组件的使用
  • NutUI 主题和样式定制
  • 国际化项目中使用 NutUI

为什么是她

Vue 给大家带来了组件化,这个功能给开发人员带来了强大并且简洁的复用组件能力。设计精美,扩展良好的组件无疑会让产品效果更加统一,带来更好的观看感觉,减少大量重复性工作,提高代码的可维护性。

  • 安装 & 引入:支持 NPM 方式和 CDN 方式,并支持按需引入
  • 丰富的 feature:丰富的组件,自定义主题,国际化
  • 文档 & demo:提供友好的文档和 demo,支持多语言
  • 工程化:开发,测试,构建,部署,持续集成

当然了,最后这个组件库还应该有持续的更新和维护。我们找了很多组件进行分析测评。先来看一下这一期关于 NutUI 的上手结果。

什么是 NutUI

NutUI 是一款非常优秀的移动端组件库。50+组件覆盖,包含基础类、数据录入类、操作反馈类、数据展示类、导航类、布局类和业务类组件。而且组件风格统一,开发人员的持续维护,保证了组件的健壮性和可维护性,满足多数场景M端需求。同时优秀的文档和活跃的社区支持,给使用者带来最优的体验。

bAV3iqI.jpg!web

NutUI 从2017年开始发版,所有组件均是从京东的业务中抽离出来,然后不断整合修复,最终发展成型。专业的标准设计稿保证一致性,优秀的组件自动化测试和不断的更新保证组件的稳定性。能够解决目前市面上多数基于 Vue 开发的 M 端需求,加快使用者开发进度。那么下面我们就带大家走进 NutUI。

开始上手

我们依据 NutUI 2.2.2 版本的源码来分析该组件库的使用和注意事项。当然,NutUI 早期一定不是这样子的,我们分析的这个版本已经是经过它多次迭代优化后的,如果你想去了解它的发展历程,可以去 https://github.com/jdf2e/nutu... 搜索它的历史版本。同时,NutUI 也在进行 3.0 版本的开发。 3.0 版本中将会独立出 Nut-CLI,同时支持 Vue3.0 的语法,全新的组件和规范。期待你的加入。(想要成为 NutUI 的维护者吗?欢迎去 https://github.com/jdf2e/nutu... 中 issue 留言和加入)

ayAzIjv.jpg!web

安装引入

目前主流的库都支持 CDN 引入和 NPM 安装。NutUI 不例外,还更有亮点。

CDN 引入

先说一下 CDN 引入。我们只要在我们的 HTML 页面上加入如下代码,就可以完整的使用 NutUI 了。

<!-- 生产环境版本,优化了尺寸和速度 -->
<!-- 引入样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@nutui/nutui/dist/nutui.min.css">
<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<!-- 引入组件库 -->
<script src="https://cdn.jsdelivr.net/npm/@nutui/nutui/dist/nutui.min.js"></script>

当然,NutUI 在这方面比较优秀的就是可以 CDN 按需加载引入。 (下面实例为只引入 Button 组件)

<body>
 <div id="app"><nut-button>CDN按需加载</nut-button></div>

 <!-- 开发环境版本,包含了有帮助的命令行警告 -->
 <!-- 引入样式 -->
 <link rel="stylesheet"href="https://cdn.jsdelivr.net/npm/@nutui/nutui/dist/packages/button/button.css"/>
 <!-- 引入Vue -->
 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 <!-- 引入组件库 -->
 <script src="https://cdn.jsdelivr.net/npm/@nutui/nutui/dist/packages/button/button.js"></script>
 <script>
  Vue.component(button.default.name, button.default);
  new Vue({
     el: "#app"
  });
 </script>
 </body>

注意,CDN 引入使用组件的时候。由于 HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,组件中的 prop 属性 camelCase (驼峰命名法) 需要使用其等价的 kebab-case (短横线分隔命名) 命名。详情参考 Prop用法

NPM 引入

NPM 引入的方式也非常简洁。我们使用 Vue-CLI 或者 Gaea CLI 搭建项目之后。在入口文件添加如下代码。

Gaea CLI 也是一款 Vue 技术栈单页面构建工具。且支持一键上传,TypeScript ,Skeleton等特色功能

import Vue from 'vue';
import Nutui from '@nutui/nutui';
import '@nutui/nutui/dist/nutui.css';

Nutui.install(Vue);

当然,如上引入的好处是方便,只需要三行代码就可以完整地使用 NutUI 所有的组件,但缺点也很明显,引入的组件包体积很大,通常一个项目也用不到所有的组件,会有资源浪费。

所以最佳方案推荐按需引入。在需要使用某组件的页面添加如下代码:(以下为 dialog , picker 组件按需加载)

import Vue from 'vue';
import { Dialog,Picker } from '@nutui/nutui';

Dialog.install(Vue);
Picker.install(Vue);

在这里说明一下,NutUI 会主动打包对应组件的 css 代码,而不像其他组件库直接打包所有css。

当我们这样使用的时候,觉得理所应当,那么为什么 import { Dialog } from '@nutui/nutui'; 可以实现按需引入呢?

实际上我们查看源码可以得到,NutUI 借助 webpack 的 @nutui/babel-plugin-seperate-import 组件实现将

import { Dialog } from '@nutui/nutui';

转换成如下代码

import Dialog from '@nutui/nutui/dist/packages/button/button.js'; // 加载构建后的JS
import '@nutui/nutui/dist/packages/button/dialog.css'; //加载构建后的CSS

同时,NutUI 在构建的时候,已经构建出一个完整版的组件库包和每个组件独立的包。然后我们手动使用 Dialog.install(Vue) 进行注册。这样我们就精准地引入了对应 lib 下的 Dialog 组件的 JS 和 CSS 代码了。实现了我们的目标:按需加载。

webpack 的中如何构建多个 bundle 呢?主要是 entry 选项的配置, entry 的值通常是一个字符串,其实它还可以是一个对象。我们新增一个 webpack 配置文件,基于组件库的组件配置文件生成一个对象,key是组件名,value是组件的入口js文件,将此对象作为该配置文件的 entry 选项值即可,其他配置与完整版的组件库 webpack 配置文件一致(输出目录可根据需要自行配置)。构建时执行这两个配置文件,即可构建出一个完整版的组件库包和每个组件独立的包

const cptConf = require('../src/config.json');
const entry = {};
//遍历所有组件
cptConf.packages.map((item)=>{
    entry[cptName] = `./src/packages/${item.name.toLowerCase()}/index.js`;
});

module.exports = {
    entry
};

组件开箱即用

JVvQVb2.png!web

上面我们已经完整的引入了 NutUI,接下来,我们将使用案例来看一下如何使用组件。

使用前准备

我们在使用一个组件库的时候,最好在 NutUI 官网上提前把该库所有的组件全部通读一遍。这样,不仅使我们对组件库有一个完整的印象,而且更有利于我们在使用组件的时候具有更多选择性。比如以下一个案例:

一个 app 开发中,进入项目后,常常会出现一个协议的提示,如图:

IRniI3m.png!web

大家是不是一下子就想到了使用 Dialog 组件,但是在使用过程中,发现内容过长,而且基础的 Dialog 不支持内容自定义,更不支持内容的滚动。这个时候是不是束手无策?其实,换种方式,使用 Popup 组件,然后居中展示,内容全部支持自定义,不就完美的解决了我们的需求。所以建议大家在使用前通读一下所有组件,磨刀不误砍柴工,反而更加有效的提高开发效率。

渐入佳境

组件了解结束之后,正式进入开发,激动人心的时候终于到了。我们先来看几个常规的组件。

日历组件:日历组件开发过程中常见的刚需组件,一个优秀的日历组件需要包含能够选择日期,区间选择等功能。

NutUI 的日历组件的日历区间选择功能,支持同一天的选择。比如选择2020/05/20-2020/05/20,这可是其他组件不支持的功能哦!

我们使用按需引入的方法来使用日历组件,在 main.js 中加载日历组件

import { Calendar } from '@nutui/nutui';
Calendar.install(Vue);

接下来我们在需要的页面中添加指定组件

<nut-calendar 
 :is-visible.sync="isVisible2"
 :default-value="data2"
 :is-auto-back-fill="true"
 @close="switchPickerClose('isVisible2')"
 @choose="setChooseValue2"
>
</nut-calendar>

<nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible2')">
     <span slot="title"><label>日期选择</label></span>
     <span slot="sub-title">有默认日期,选择后自动回填的~~~</span>
     <div slot="desc" class="selected-option" >
       <span class="show-value">{{date2 ? date2 : '请选择日期'}}</span>
     </div>
 </nut-cell>

// js部分
export default {
 data() {
   return {
     isVisible2: false,
     date2: '2020-12-22',
   };
 },
 methods: {
   setChooseValue2(param) {
     this.date2 = param[3];
   },
   switchPickerClose(isVisible2){
    this.isVisible2=!this.isVisible2;
   }
 }
};

上面代码中,is-visible.sync 是来控制日历是否展示,default-value 是展示日历的默认日期,close 是关闭事件,choose是我们选择日期的事件触发。默认日历组件时不显示的,我们需要通过点击 Cell 来控制日历组件,这样一个完整的日历效果就实现了,剩下的就是我们处理自己的业务了!

思考 : 为什么要使用 .sync ?

除了日历组件这种需要在页面上放置组件来展示的,部分组件支持直接函数式调用,比如 Dialog组件,我们来体验一下。

先全局注册 Dialog 组件。

import { Button , Dialog } from '@nutui/nutui';
Button.install(Vue);
Dialog.install(Vue);

然后我们在按钮上添加一个事件,在事件中使用dialog

<nut-button 
 @click="clickHandler"
>
 提交
</nut-button>

//js部分
export default {
 data() {},
 methods: {
   clickHandler() {
     this.$dialog({
       title: "提交",
       content: "你确定提交当前数据吗",
       closeBtn:true, //显式右上角关闭按钮
       onOkBtn(event) { //确定按钮点击事件
        alert("okBtn");
        this.close(); //关闭对话框
       },
       onCancelBtn(event) { //取消按钮点击事件,默认行为关闭对话框
        alert("cancelBtn");
        //return false; //阻止默认“关闭对话框”的行为
       },
       onCloseBtn(event) { //右上角关闭按钮点击事件
        alert("closeBtn");
        //return false; //阻止默认“关闭对话框”的行为
       },
       closeCallback(target) {
        alert("had close"); //对话框关闭回调函数,无论通过何种方式关闭都会触发
       }
    });
   }
 }
};

um6jqiz.png!web

dialog 的内容不仅支持文字,同时支持图片类型。

this.$dialog({
 type:"image", //设置弹窗类型为”图片弹窗“
 link:"http://m.jd.com", //点击图片跳转的Url
 imgSrc:"m.360buyimg.com//5b9549eeE4997a18c/070eaf5bddf26be8.jpg", //图片Url
 onClickImageLink:function(){ 
    //图片点击事件,默认行为是跳转Url
    console.log(this);
    //返回false可阻止默认的链接跳转行为
 }
});

nMbiqmB.png!web

为什么我们使用 Dialog 可以直接通过 this 来直接调用呢?原因就是 Dialog 组件在构建的时候,其实构建了两种:一种支持我们使用组件式使用,另一种支持我们使用函数式调用。

import DialogVue from './dialog.vue';
import Dialog from './_dialog';
import './dialog.scss';

const DialogArr = [Dialog, DialogVue];

DialogArr.install = function(Vue){
Vue.prototype['$dialog'] = Dialog;
Vue.component(DialogVue.name, DialogVue);
}

上面代码我们可以看到,Dialog 构建时,不仅使用了 Vue.prototype 来扩展一个新的方法,同时也使用了 Vue.component 来实现组件式调用。

额外惊喜

NutUI 中目前不仅有传统的通用组件,现在也在逐渐增加好多特色组件。比如目前已经有的抽奖组件和签名组件。先去官网一睹为快吧!

N3Qb6rU.gif nUJVnyF.gif

(更多组件和使用方法参考官网文档 https://nutui.jd.com/ )

主题定制

使用任何一个组件功能可以类似,但样式却是各式各样。如何在使用 NutUI 的基础上实现自己的样式定制呢?

全局定制

首先我们来看,NutUI 中所有公共的样式都在 diststylesvariable.scss 中。当我们想要修改的时候,可以在项目中创建一个 scss 文件,然后复制公共样式中所有变量。

我们需要修改一下配置。在vue.config.js 的 css 配置或者 webpack 中的 sass-loader 的配置。引入我们自定义的 scss 文件,注意属性哦。

module.exports = {
 css: {
   loaderOptions: {
     // 给 sass-loader 传递选项
     scss: {
       // @/ 是 src/ 的别名
       // 注意:在 sass-loader v7 中,这个选项名是 "data"
       prependData: ` 
       @import "@/assets/custom_theme.scss"; //这个是我们自定义的scss文件@import "@nutui/nutui/dist/styles/index.scss";
       `,
     }
   },
 }
}

然后我们使用组件的时候,需要引入 SCSS 文件,而不是 CSS 文件。这样变完成了对 NutUI 的全局样式定制。

import Nutui from '@nutui/nutui';
import '@nutui/nutui/dist/nutui.scss';

私人定制

当然,如果我们项目中某个特殊组件需要修改样式,而且不想影响该组件在其他地方的使用,我们可以在页面上直接使用 /deep/ 进行样式修改,但是注意添加对样式style 添加 scoped 哦!

/deep/ 是Vue提供的深度选择器。详情参考 VUE官网 Scope CSS

国际化

随着越来越多的多语言项目进入我们的开发需求中。国际化方案成为一种必需品。谈到 Vue 的国际化方案,大家很容易会联想到 vue-i18n 方案,NutUI 并未引入 vue-i18n,不过它是可以很好地兼容 vue-i18n 。

NutUI 的国际化

所有的国际化方案都会用到语言包,语言包通常会返回一个 JSON 格式的数据,NutUI 组件库的语言包在 locale/lang 目录下。我们使用的时候,需要在引入 NutUI 的时候同时引入对应的语言包。如下是引用了英语语言包。

import Vue from 'vue';
import NutUI from '@nutui/nutui';
import enUS from '@nutui/nutui/dist/locales/lang/en-US';

Vue.use(NutUI , {
 locale: 'en-US',
 lang: enUS
});

这样我们的页面中所有关于 NutUI 组件的都会使用英语语言展示,如图:

qMB3maM.png!web

整个项目的国际化

当然,这只是修改了组件内部的语言,如何将 NutUI 和自己的语言包完美融合呢?我们构建一个自己的语言包。

// zh_cn.js文件
export default {
 app: {
   hello: '你好,世界!'
 }
}

// en_us.js文件
export default {
 app: {
   hello: 'Hello,World!'
 }
}

然后再入口文件中进行引入。

import Vue from 'vue';
import VueI18n from 'vue-i18n';
import {locale} from '@nutui/nutui';
import enUS from '@nutui/nutui/dist/locales/lang/en-US';
import zhCN from '@nutui/nutui/dist/locales/lang/zn-CH';
import enLocale from './en_us';
import zhLocale from './zh_cn';

Vue.use(VueI18n);
Vue.locale = () => {};
// 将语言包进行合并
const messages = {
 en: {
 ...enUS,
 ...enLocale
 },
 zh: {
 ...zhCN,
 ...zhLocale
 }
}

const i18n = new VueI18n({
 locale: 'zh', // 设置默认语言
 messages: messages // 设置资源文件对象
})
//
const app = new Vue({
 el: '#app',
 i18n
})

这样便将 i18n 和我们 NutUI 的语言包进行了合并。如何在页面中使用呢?

<template>
  <nut-navbar :title="$t('app.hello')" @click-left="show=true">
  </nut-navbar>
</template>

我们在 JS 中使用的时候需要加上 this。例如:

created () {
 console.log('start to enter created ', this.$t('app.hello'))
}

接下来,我们在语言切换的按钮上绑定如下事件,即可完美的实现语言切换功能了。

tabEn: function () { 
 this.$i18n.locale = 'en' 
}, 
tabCn: function () { 
 this.$i18n.locale = 'zh' 
}

这样,我们就完美的实现了多语言的展示和切换功能。是不是很优秀?

文档 & Demo

当我们使用一个组件库的时候,友好的文档和 Demo 是必不可少的。她可以让我们更方便快捷的使用。NutUI 的 Demo 和文档是分开的。从 NutUI 的Github 中可以看出,NutUI 把所有的组件都放在 src/packages 下面。每一个组件大概由下面几部分组成。

ZBnqaaJ.png!web

其中_test 文件夹内是组件的单元测试。NutUI 如何进行单元测试可参考文章 NutUI单元测试实践 。其中详细介绍了如何编写单元测试和在 NutUI 中单元测试实践。

剩下的文件中以组件命名的 js ,vue , css 文件,是该组件的核心。上面也介绍了一个组件是如何从0开始构建的,一个通用的组件从参数传入,参数处理,校验,参数存储,function 回调等各种特性保证才产出。

demo.vue 文件包含了该组件各种常规用法。我们官网上所有的实例写法,都可以在对应组件的 demo 文件种找到。同学们可以如果有需求,可以只看 demo ,来 copy 你想要的功能哦!

最后我们说到的是.md 文件。md 文件就是我们官网上对该组件的说明和使用方法,我们是如何将 md 直接变成我们的官网呢, 点击这里 可以得到答案哦!

结束语

至此,关于NutUI 的基本使用,我们今天就先介绍到这里。是不是很心动,赶快在你的项目中使用起来吧!同时 NutUI 交流咚咚群(82957939) 期待你的加入。本文中所有的示例都收录在 https://github.com/jdf2e/nutu... 欢迎访问点赞!!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK