合格前端系列第八弹-造一个属于自己的 UI 库

简介:

一、项目介绍

vui : 一个私人的vue ui 组件库(移动端为主)

文档官网

已有组件

二、安装下载

npm install x-vui -S

三、快速开始

3.1 构建项目(配合vue-cli)

# 全局安装 vue-cli
npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
vue init webpack my-vui-project
# 安装依赖,并下载x-vui
cd my-vui-project
npm install && npm install x-vui
# 项目启动 默认端口localhost:8080
npm run dev

3.2 引入vui组件库

你可以引入整个 vui,或是根据需要仅引入部分组件。我们先介绍如何引入完整的 vui。

3.2.1 完整引入

在main.js中写入

import Vue from 'vue'
import vui from 'x-vui'
import 'x-vui/lib/vui-css/index.css';

Vue.use(vui)

3.2.2 按需部分引入

在main.js中写入(假如我只需要Scroller和Select组件)

import Vue from 'vue'
import {
  Scroller,
  Select
  // ...
} from 'x-vui'
import 'x-vui/lib/vui-css/scroller.css';
import 'x-vui/lib/vui-css/select.css';

Vue.component(Scroller.name, Scroller)
Vue.component(Select.name, Select)

3.2.3 全局注册vui插件

注:完整引入了vui,则无需再注册插件

import Vue from 'vue';
import { 
  $Toast, 
  $Dialog 
  // ...
} from 'x-vui';

Vue.prototype.$toast = $Toast
Vue.prototype.$dialog = $Dialog


四、组件用法

4.1 swiper

可以自己调配自己想要的swiper,不一定得是轮播图

4.1.1 Attributes

参数 说明 类型 可选值 默认值
type swiper类型 string swiper(正常)/thum(缩略) swiper
auto 自动播放时长 number 5000
items swiper展示的列表 array []
showIndicators 是否展示swiper小圆点 boolean true
styles swiper样式控制 object {}
resetTitle 重置title内容 string

4.1.2 Events

事件名称 说明 回调参数
change swiper滑动回调 当前swiper item索引

4.1.3 用法

<template>
  <div class="swiper-page">
    <p>正常swiper</p>
    <x-swiper type='swiper' :items='items' :styles="{height: '180px'}"></x-swiper>
    <p>缩略swiper</p>
    <x-swiper type='swiper' :items='items' :type="'thum'" :styles="{height: '208px'}"></x-swiper>
  </div>
</template>

<script>
export default {
  data () {
    return {
      items: [
        require('assets/beauty_1.png'),
        require('assets/beauty_2.png'),
        require('assets/beauty_3.png'),
        require('assets/beauty_4.png'),
        require('assets/beauty_5.png')
      ],
    }
  }
}
</script>

<style lang="stylus" scoped>
.swiper-page {
  height auto
}
</style>

4.2 scroller(下拉刷新上拉加载)

4.2.1 Attributes

参数 说明 类型 可选值 默认值
onRefresh 下拉回调 function
onInfinite 上拉回调 function
width scroller宽度 string 100%
height scroller高度 string 100%
isLoadMore 是否展示上拉加载 boolean true
refreshText 下拉文本内容 string 下拉刷新
noDataText 无数据文本 string 没有更多数据啦~
refreshLayerColor 下拉文本颜色 string #AAA
loadingLayerColor 上拉文本颜色 string #AAA
animating 是否有动画 boolean true
animationDuration 动画间隔 number 250
bouncing 是否有反弹效果 string true
cssClass content css class string

4.2.2 用法

<style scoped>
.scroller-page {
  height: 330px
}
ul {
  padding: 20px 0
}
li {
  width: 100%;
  height: 35px;
  line-height: 35px;
  border-bottom: 1px solid #eee;
  text-align: center;
}
</style>

<template>
  <div class="scroller-page">
    <x-scroller
      :on-refresh="refresh"
      :on-infinite="infinite"
      :noDataText="noDataText"
    >
      <!-- content is here -->
      <ul>
        <li>数据1</li>
        <li>数据2</li>
        <li>数据3</li>
        <li>数据4</li>
        <li>数据5</li>
        <li>数据6</li>
      </ul>
    </x-scroller>
  </div>
</template>

<script>
export default {
  data () {
    return {
      noDataText: '没有更多数据啦~'
    }
  },
  methods: {
    refresh (done) {
      setTimeout(done, 1000)
      this.noDataText = ''
      console.log('refresh');
    },
    infinite (done) {
      setTimeout(done, 1000, true)
      this.noDataText = '没有更多数据啦~'
      console.log('infinite');
    }
  }
}
</script>

4.3 search

4.3.1 Attributes

参数 说明 类型 可选值 默认值
async 是否进行节流 boolean true
timeout 搜索节流时长 number 100
styles search样式 object
placeholder placeholder string '搜索'
autofocus 是否自动聚焦(iOS端autofocus无效) boolean
clear 进行搜索是否清空search框内容 boolean false

4.3.2 Events

事件名称 说明 回调参数
search search搜索回调 搜索文本
enter enter时搜索回调 搜索文本
close 点击搜索关闭按钮回调 ''

4.3.3 用法

只有搜索框

<style lang="stylus">
.search-page {
  padding: 0 10px;
  margin-top: 10px;
}
</style>
<template>
  <div>
    <x-search
      placeholder="请输入搜索关键字"
      @search="searchFn"
      @enter="searchEnter"
      @close="closeFn"
    ></x-search>
  </div>
</template>

<script>
export default {
  methods: {
    searchFn (query) {
      console.log('search', query)
    },
    searchEnter (query) {
      console.log('enter', query)
    },
    closeFn (query) {
      console.log('close', query)
    }
  }
}
</script>

拥有默认的搜索结果列表

<style lang="stylus">
.search-page {
  padding: 0 10px;
  margin-top: 10px;
}
</style>
<template>
  <div class="search-page" v-title data-title="search">
    <x-search
      placeholder="请输入搜索关键字"
      :autofocus="true"
      :async="false"
      @search="searchFn"
      @enter="searchEnter"
      @close="closeFn"
    >
      <x-search-list :result="filterResult" @listSearch="listSearch" v-show="visible"></x-search-list>
    </x-search>
  </div>
</template>

<script>
export default {
  data () {
    return {
      keyword: '',
      visible: false, // 点击列表,列表是否消失
      defaultResult: [
        'Apple',
        'Banana',
        'Orange',
        'Durian',
        'Lemon',
        'Peach',
        'Cherry',
        'Berry',
        'Core',
        'Fig',
        'Haw',
        'Melon',
        'Plum',
        'Pear',
        'Peanut',
        'Other'
      ]
    }
  },
  watch: {
    keyword (val) {
      if (!val) {
        this.visible = false;
      }
    }
  },
  methods: {
    searchFn (query) {
      this.keyword = query;
      this.visible = true;
      console.log('search', query)
    },
    searchEnter (query) {
      this.keyword = query;
      console.log('enter', query)
    },
    closeFn (query) {
      this.keyword = query;
      console.log('close', query)
    },
    listSearch (index) {
      this.visible = false;
      console.log(index, this.defaultResult[index])
    }
  },
  computed: {
    filterResult() {
      return this.defaultResult.filter(item => new RegExp(this.keyword, 'i').test(item));
    }
  }
}
</script>

定制化结果列表,关键字高亮匹配

<style lang="stylus">
.search-page {
  padding: 0 10px;
  margin-top: 10px;

  .search-result {
    position: relative;
    overflow: hidden;
    .l {
      width: 100%;
      margin-bottom: 5px;
    }
    .r {
      position: absolute;
      right: 0;
      top: 50%;
      margin-top: -10px;
      line-height: 20px;
    }
    .price {
      color: #ff6f5c;
    }
    .gray {
      font-size: 12px;
    }
  }
}
</style>
<template>
  <div class="search-page" v-title data-title="search">
    <x-search
      placeholder="请输入搜索关键字"
      :autofocus="true"
      :async="false"
      @search="searchFn"
      @enter="searchEnter"
      @close="closeFn"
    >
      <x-search-list :result="filterResult" @listSearch="listSearch" v-show="visible">
        <div class="search-result" slot="list-item" slot-scope="props">
          <p class="l" v-html="props.slotValue.name"></p>
          <p class="gray" v-show="props.slotValue.price">¥{{props.slotValue.price}}/斤</p>
          <div class="gray r" v-show="props.slotValue.amount">剩余{{props.slotValue.amount}}斤</div>
        </div>
      </x-search-list>
    </x-search>
  </div>
</template>

<script>
export default {
  data () {
    return {
      keyword: '',
      visible: false,
      defaultResult: [
        {name: 'Apple', price: 5, amount: 20},
        {name: 'Banana', price: 5, amount: 30},
        {name: 'Orange', price: 3, amount: 10},
        {name: 'Durian', price: 10, amount: 25},
        {name: 'Lemon', price: 4, amount: 30},
        {name: 'Peach', price: 5, amount: 40},
        {name: 'Cherry', price: 20, amount: 50},
        {name: 'Berry', price: 15, amount: 60},
        {name: 'Core', price: 10, amount: 21},
        {name: 'Fig', price: 10, amount: 22},
        {name: 'Haw', price: 10, amount: 23},
        {name: 'Melon', price: 10, amount: 24},
        {name: 'Plum', price: 10, amount: 25},
        {name: 'Pear', price: 10, amount: 26},
        {name: 'Peanut', price: 10, amount: 27},
        {name: 'Other'}
      ],
      // 防止defaultResult值被污染
      copy: []
    }
  },
  watch: {
    keyword (val) {
      if (!val) {
        this.visible = false;
      }
    }
  },
  methods: {
    searchFn (query) {
      this.keyword = query;
      this.visible = true;
      console.log('search', query)
    },
    searchEnter (query) {
      this.keyword = query;
      console.log('enter', query)
    },
    closeFn (query) {
      this.keyword = query;
      console.log('close', query)
    },
    listSearch (index) {
      this.visible = false;
      console.log(index, this.defaultResult[index].name)
    }
  },
  computed: {
    filterResult() {
      // i 忽略大小写
      let result = this.defaultResult.filter(item => new RegExp(this.keyword, 'i').test(item.name));
      // 关键字高亮匹配
      this.copy = JSON.parse(JSON.stringify(result))
      this.copy.forEach((item, index) => {
        let name = item.name, word = this.keyword;
        name = name.toLowerCase();
        word = word.toLowerCase();

        if (word && name.indexOf(word) !== -1) {
          let arr    = item.name.split('')
          let i      = name.indexOf(word);
          let len    = word.length;
          let active = '<span class="price">' + arr.splice(i, len).join('') + '</span>';
          arr.splice(i, 0, active);
          item.name  = arr.join('');
        }
      })
      return this.copy;
    }
  }
}
</script>

4.4 dialog

4.4.1 Attributes

message

参数 说明 类型 可选值 默认值
msg msg文本内容 string
timeout msg显示时长 number 2000
callback 回调函数 function
icon 特殊icon string

modal

参数 说明 类型 可选值 默认值
show modal是否显示 boolean
title modal标题 string
content modal内容 string
onOk 确定按钮回调 function
onCancel 取消按钮回调 function
okText 确定按钮内容 string
cancelText 取消按钮内容 string
showCloseIcon 是否显示关闭icon boolean true

4.4.2 用法

msg

this.$dialog.msg({msg: 'hello message components ~'})

modal(插件)

this.$dialog.modal({
  title: 'Demo Modal',
  cancelText: '取消',
  okText: '确定',
  content: '测试,测试,测试,测试,测试,测试,测试,测试,测试',
  onOk () {
    console.log('click ok btn to do someting');
  },
  onCancel () {
    console.log('click cancel btn to do someting');
  }
})

modal(组件)

<style lang="stylus">
.dialog-page {
  .dialog-btn {
    width 100%
    position absolute
    top 50%
    left 0
    transform translateY(-50%)
    > p {
      width 80%
      height 50px
      line-height 50px
      margin 40px auto 0
      border 1px solid #CCC
      border-radius 10px
      font-size 16px
      font-weight bold
      letter-spacing 2px
      text-align center
      &:first-child {
        margin-top 0
      }
    }
  }
  .modal-text {
    text-align: center;
  }
}
</style>
<template>
  <div class="dialog-page">
    <div class="dialog-btn">
      <p @click="message">message dialog</p>
      <p @click="open">modal dialog</p>
    </div>
    <x-modal title="Demo Modal" cancelText="取消" :onCancel="close" :show="selectModel" okText="确认" :onOk="close">
      <p class="modal-text">modal components test is awesome!!!</p>  
    </x-modal>
  </div>
</template>

<script>
export default {
  data () {
    return {
      selectModel: false
    }
  },
  methods: {
    message () {
      return this.$dialog.msg({msg: 'this is a message dialog'})
    },
    open () {
      this.selectModel = true
    },
    close () {
      this.selectModel = false
    }
  }
}
</script>

4.5 table

4.5.1 Attributes

参数 说明 类型 可选值 默认值
tableData table数据 array
label thead标题(TableColum)  
prop 绑定的数据 string

4.5.2 用法

配合scroller进行展示(注:目前table较为简单,后期将进行完善,使得其可以应对不同场景)

<template>
  <div class="table" v-title data-title="table">
    <x-scroller
      :on-refresh="refresh"
      :on-infinite="infinite"
      :noDataText="noDataText"
      class="table-content"
    >
      <x-table :tableData="items">
        <x-table-column prop="list_1" label="LIST ONE"></x-table-column>
        <x-table-column prop="list_2" label="LIST TWO"></x-table-column>
        <x-table-column prop="list_3" label="LIST THREE"></x-table-column>
        <x-table-column prop="list_4" label="LIST FOUR"></x-table-column>
      </x-table>
    </x-scroller>
  </div>
</template>

<script>
export default {
  data () {
    return {
      items: [
        {
          list_1: '2017.12.09',
          list_2: '路人1',
          list_3: '爱过',
          list_4: '有'
        },
        {
          list_1: '2017.12.10',
          list_2: '路人2',
          list_3: '爱过',
          list_4: '有'
        },
        {
          list_1: '2017.12.11',
          list_2: '路人3',
          list_3: '爱过',
          list_4: '没有'
        },
        {
          list_1: '2017.12.12',
          list_2: '路人4',
          list_3: '爱过',
          list_4: '没有'
        }
      ],
      noDataText: '没有更多数据啦~'
    }
  },
  methods: {
    refresh (done) {
      setTimeout(done, 1000)
      this.noDataText = ''
      console.log('refresh');
    },
    infinite (done) {
      setTimeout(done, 1000, true)
      this.noDataText = '没有更多数据啦~'
      console.log('infinite');
    }
  }
}
</script>

4.6 picker

4.6.1 Attributes

参数 说明 类型 可选值 默认值
default picker默认选中的值 string/number
type picker类型 string date/time/datetime/custom datetime
title 选择器弹窗标题 string
placeholder placeholder string 请选择时间
timeStep 时间选择粒度(有分钟的选择器) number 1
startYear 起始年份 number/string 今年
endYear 结束年份 number/string 10年的范围
startDate 起始日期 string
endDate 结束日期 string
startHour 起始时间 number/string 0
endHour 结束时间 number/string 23
startMinute 起始分钟 number/string 0
endMinute 结束分钟 number/string 59
yearFormat “年“的格式化 string '{value}年'
monthFormat “月“的格式化 string '{value}月'
dayFormat “日“的格式化 string '{value}日'
hourFormat “时“的格式化 string '{value}时'
minuteFormat “分“的格式化 string '{value}分'

4.6.2 用法

<style lang="stylus">
.picker-page {
  .x-list {
    padding: 0 0.32rem;
    background: #fff;
    color: #333;
    font-size: 14px;

    > li {
      min-height: 60px;
      padding-top: 21px;
      border-bottom: 1px solid #f2f2f2;
      overflow: hidden;

      > label {
        float: left;
      }

      > div {
        float: right;
      }

      .x-list-arrow {
        min-width: 100px;
        margin-right: 10px;
        position: relative;

        > div {
          float: right;
          text-align: right;
          margin-right: 10px;
        }

        &:after {
          content: '';
          position: absolute;
          top: 4px;
          right: -5px;
          width: 10px;
          height: 10px;
          border-top: 1px solid #ccc;
          border-right: 1px solid #ccc;
          transform: rotate(45deg);
          -webkit-transform: rotate(45deg);
        }
      }
    }
  }
}
</style>

<template>
<div class="picker-page" v-title data-title="picker">
  <ul class='x-list'>
    <li>
      <label>日期选择</label>
      <div class="x-list-arrow">
        <x-picker title="选择日期" startYear="2016" startDate="2015-01-01" endDate="2019-12-01"  placeholder="请选择日期" v-model="now_date" type="date"></x-picker>
      </div>
    </li>
    <li>
      <label>时间选择</label>
      <div class="x-list-arrow">
        <x-picker title="选择时间" placeholder="请选择时间" startMinute="2" endMinute="30" v-model="now_time" type="time"></x-picker>
      </div>
    </li>
    <li>
      <label>日期时间选择</label>
      <div class="x-list-arrow">
        <x-picker title="选择日期时间" placeholder="请选择日期时间" v-model="now_datetime" :timeStep="20" type="datetime"></x-picker>
      </div>
    </li>
    <li>
      <label>性别选择</label>
      <div class="x-list-arrow">
        <x-picker v-model="gender.value" placeholder="请选择性别" :default="gender.default" title="选择性别" type="custom"></x-picker>
      </div>
    </li>
  </ul>
</div>
</template>

<script>
export default {
  data() {
    return {
      gender: {
        default: -1,
        value: [
          {
            name: "保密",
            value: 0
          },
          {
            name: "男",
            value: 1
          },
          {
            name: "女",
            value: 2
          }
        ]
      },
      now_date: null,
      now_time: null,
      now_datetime: null // new Date().getTime()/1000
    };
  }
};
</script>

4.7 select

4.7.1 Attributes

参数 说明 类型 可选值 默认值
selectData 下拉数据 array []
title 默认显示的标题 string ''
alwaysShowTitle 是否一直显示默认标题 boolean false
defaultValue 默认选中的值 number/string 0
width select组件的宽度 string '100%'
ellipsisWidth select文字超过多出省略号的宽度 string '120px'

4.7.2 Events

事件名称 说明 回调参数
search select 选择时的回调函数 参数1:索引,参数2:所中项的id值

4.7.3 用法

<template>
  <div class="select-page" v-title data-title="select">
    <x-select
      @search="searchFn"
      :selectData="selectData"
      title="LIST ONE"
      :alwaysShowTitle="false"
      width="50%"
      defaultValue="0"
    ></x-select>
    <x-select
      @search="searchFn1"
      :selectData="selectData1"
      title="LIST TWO"
      width="50%"
      ellipsisWidth="65px"
      defaultValue="1"
    ></x-select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selectData: [
        { id: 1, name: "LIST ONE 1" },
        { id: 2, name: "LIST ONE 2" },
        { id: 3, name: "LIST ONE 3" },
        { id: 4, name: "LIST ONE 4" },
        { id: 5, name: "LIST ONE 5" }
      ],
      selectData1: [
        { id: 1, name: "LIST TWO 1" },
        { id: 2, name: "LIST TWO 2" },
        { id: 3, name: "LIST TWO 3" },
        { id: 4, name: "LIST TWO 4" },
        { id: 5, name: "LIST TWO 5" }
      ]
    };
  },
  methods: {
    searchFn(index, id) {
      console.log(index, id);
    },
    searchFn1(index, id) {
      console.log(index, id);
    }
  }
};
</script>

4.8 dropdown

这个下拉菜单偏PC端的这里就不多做介绍了

<template>
  <div class="test">
    <x-dropdown trigger="click" @command="commandHandle" :hide-on-click="true">
        <span class="drop-down_link">下拉菜单</span>
        <x-dropdown-menu>
            <x-dropdown-list command="a">下拉列表1</x-dropdown-list>
            <x-dropdown-list command="b">下拉列表2</x-dropdown-list>
            <x-dropdown-list command="c"><h4>下拉列表3</h4></x-dropdown-list>
        </x-dropdown-menu>
    </x-dropdown>
  </div>
</template>

<script>
export default {
  name: 'Dropdown',
  methods: {
    commandHandle (command, instance) {
      console.log(command, instance);
    }
  }
}
</script>


以上组件便是目前vui所有的组件了,后期会不断的进行维护并进行新组件的开发。


本文作者:qiangdada
本文发布时间:2017/12/14
本文来自云栖社区合作伙伴 开源中国,了解相关信息可以关注oschina.net网站。
目录
相关文章
|
21天前
|
人工智能 API Apache
推荐3款开源、美观且免费的WinForm UI控件库
推荐3款开源、美观且免费的WinForm UI控件库
|
1月前
|
前端开发 JavaScript
除了 jsPDF,还有哪些前端库可以用于生成 PDF?
【10月更文挑战第21天】这些前端库都有各自的特点和优势,你可以根据具体的项目需求、技术栈以及对功能的要求来选择合适的库。不同的库在使用方法、性能表现以及功能支持上可能会有所差异,需要根据实际情况进行评估和选择。
|
21天前
|
API C# 开发者
基于Material Design风格开源、免费的WinForms UI控件库
基于Material Design风格开源、免费的WinForms UI控件库!
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
存储 前端开发 JavaScript
🚀 10 个 GitHub 存储库,助你成为前端巨匠✨
本文介绍了10个极具价值的GitHub存储库,旨在帮助各级JavaScript开发人员提升技能。这些资源涵盖了从基本概念到高级算法、编码风格指南、面试准备等各个方面,包括经典书籍、实用工具和面试手册。无论您是刚入门的新手还是有经验的开发者,这些存储库都能为您提供丰富的学习资源,助您在JavaScript领域更进一步。探索这些资源,开启您的学习之旅吧!
62 0
🚀 10 个 GitHub 存储库,助你成为前端巨匠✨
|
3月前
|
前端开发 开发者 UED
前端只是切图仔?来学学给开发人看的UI设计
该文章针对前端开发者介绍了UI设计的基本原则与实践技巧,覆盖了布局、色彩理论、字体选择等方面的知识,并提供了设计工具和资源推荐,帮助开发者提升产品的视觉与交互体验。
|
2月前
|
Linux C# Android开发
分享3款开源、免费的Avalonia UI控件库
分享3款开源、免费的Avalonia UI控件库
172 0
|
3月前
|
搜索推荐 前端开发 C#
推荐7款美观且功能强大的WPF UI库
推荐7款美观且功能强大的WPF UI库
117 2
|
4月前
|
API Android开发
Android项目架构设计问题之选择和使用合适的UI库如何解决
Android项目架构设计问题之选择和使用合适的UI库如何解决
53 0
|
4月前
|
C# 开发者 Windows
一款基于Fluent设计风格、现代化的WPF UI控件库
一款基于Fluent设计风格、现代化的WPF UI控件库
101 1