合格前端系列第八彈-造一個屬於自己的 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所有的組件了,後期會不斷的進行維護並進行新組件的開發。

vui github傳送門:https://github.com/Brickies/vui

vui npm傳送門:https://www.npmjs.com/package/x-vui

如果小夥伴們喜歡我的vui,歡迎star。

如果有什麼問題歡迎小夥伴們隨時提issue

如果有好的組件歡迎小夥伴們隨時提pr,我會不定期進行merge

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章