Vue+Element組件封裝

使用element經常需要用表格展示數據,對錶格內容進行分頁以及搜索都是比較常見的需求;於是想到了對element進行二次封裝;主要涉及的組件有el-table、el-dropdown(控制每頁展示條目數)、el-pagination(table分頁)、el-input(搜索框)。
效果預覽
在這裏插入圖片描述

創建項目

//注: el-table-ly 是項目名字
vue init webpack-simple el-table-ly

在這裏插入圖片描述
刪繁就簡:src目錄下刪除所有文件,新建lyTable.vue和main.js
在這裏插入圖片描述
二次封裝的組件如何進行數據和事件的綁定呢?
使用組件通信來進行數據和事件綁定 示例如下:

數據綁定

// lyTable.vue   子組件

    <el-table :data="data_table">
    	<slot></slot>   //此處使用slot插槽爲了方便下面父組件傳遞 <el-table-column>
    </el-table>

    props:{
        data:{}
    },
//使用封裝的組件庫 父組件 
<ly-table :data="table">
	<el-table-column prop="name" label="name"></el-table-column>
	<el-table-column prop="value" label="value"></el-table-column>
<ly-table>

    data() {
        return {
	    table:['name':'ly','value':'xixi'] 
        }
    },

事件綁定:

//lyTable.vue 子組件

	<el-table :data="data_table" @row-click="handleRowClick">
		<slot></slot>
	</el-table>
    
    	methods: {
        	handleRowClick(row, column, event){
            		this.$emit('row-click',row, column, event);
        	}
    	}
//使用封裝的組件庫 父組件 

      	<el-table :data="table" @row-click="rowClick"></el-table>
	
	data(){
	    return{
		table:['name':'ly','value','xixi']
	    }
	},
	methods:{
		rowClick(){
		    //row-click點擊事件代碼
		}
	}

進行封裝後的 lyTable.vue 代碼如下

<template>
  <div style="margin-bottom: 20px;margin: 10px 20px 10px 20px;">
    <div> 
        <div style="float:left;padding-top:10px">
        <label style="font-weight:bold;">Show</label>  
        <el-dropdown trigger="click" @command="handleCommand">
            <span class="el-dropdown-link">
                {{data_pageSize}}<i class="el-icon-arrow-down el-icon--right"></i>
            </span>
            <el-dropdown-menu slot="dropdown">
                <el-dropdown-item command="10">10</el-dropdown-item>
                <el-dropdown-item command="25">25</el-dropdown-item>
                <el-dropdown-item command="50">50</el-dropdown-item>
                <el-dropdown-item command="100">100</el-dropdown-item>
            </el-dropdown-menu>
        </el-dropdown>     
        <label style="font-weight:bold;">entries</label>  
        </div>
        <div class="search-Box" style="float:right;width:250px;height:40px;padding-right:10px;">
                <el-label style="float:left;font-weight:bold;padding-top:10px">Search:</el-label>
                <el-input style="display:inline;float:right;width:180px" prefix-icon="el-icon-search" placeholder="請輸入搜索內容"
                 icon="search" class="search" v-model="data_search"></el-input>
        </div>
    </div>
<el-table :data="(data_filter_table=tables).slice((data_currentPage-1)*data_pageSize,data_currentPage*data_pageSize)" :stripe="stripe" :border="border" :height="height" 
              :max-height="max_height" :size="size" :show-header="show_header" :highlight-current-row="highlight_current_row" :current-row-key="current_row_key" 
              :row-class-name="row_class_name" :row-style="row_style" :cell-class-name="cell_class_name" :cell-style="cell_style" :row-key="row_key" 
              :show-summary="show_summary" @select="handleSelect" @select-all="handleSelectAll" @selection-change="handleSelectionChange"
              @cell-mouse-enter="handleCellMouseEnter" @cell-mouse-leave="handleCellMouseLeave" @cell-click="handleCellClick" @row-click="handleRowClick"
              @header-click="handleHeaderClick" ref="ref_table">
        <slot></slot>
    </el-table>
    <div style="padding-top:10px;vertical-align:middle">
        Showing {{data_show_first}} to {{data_show_end}} of {{data_filter_table_length}} entries
        <span v-if="data_filter_table_length!=data_total">(filtered from {{data_total}} total entries)</span>
        <el-pagination style="float:right" layout="prev, pager, next" :page-size="data_pageSize" :total="data_filter_table.length"
         background @current-change="handleCurrentPage" :current-page="data_currentPage"></el-pagination>
    </div>
  </div>
</template>

<script>
  export default {
    props:{
        data:{},
        stripe:{default:true},
        border:{default:true},
        height:{default:null},
        max_height:{default:null},
        size:{default:null},
        show_header:{default:true},
        highlight_current_row:{default:false},
        current_row_key:{default:null},
        row_class_name:{default:null},
        row_style:{default:null},
        cell_class_name:{default:null},
        cell_style:{default:null},
        row_key:{default:null},
        show_summary:{default:false},
        ref_table:{default:null}
    },
    data() {
        return {
            data_total:100,//默認數據總數
            data_pageSize:10,//每頁的數據條數
            data_currentPage:1,//默認開始頁面
            data_search: '',  //搜索內容
            data_filter_table:[], //搜索過濾後的數據table
        }
    },
    watch:{
        tables(val){
            this.data_filter_table = val;
            this.data_currentPage = 1;
        }
    },
    computed: {
        // 模糊搜索 過濾父組件 :data傳遞給子組件的table內容
        tables:function(){
            var data_search=this.data_search;
            if(data_search){
                return  this.data.filter(function(dataNews){
                    return Object.keys(dataNews).some(function(key){
                        return String(dataNews[key]).toLowerCase().indexOf(data_search) > -1
                    })
                })
            }else{
                this.data_total = this.data.length;
            }
            return this.data;
        },
        data_pageSize(){
            return this.data_pageSize;
        },
        data_search: {
            get () {
                return this.data_search;
            },
            set (val) {
                this.data_search = val;
            }      
        },
        data_total(){
            return this.data_total;
        },
        data_filter_table_length(){
            return this.data_filter_table.length;            
        },
        data_show_first(){
            return ((this.data_currentPage-1)*(this.data_pageSize)+1)>this.data_filter_table.length?0:((this.data_currentPage-1)*(this.data_pageSize)+1);         
        },
        data_show_end(){
            return (this.data_currentPage*(this.data_pageSize))>this.data_filter_table.length?this.data_filter_table.length:(this.data_currentPage*(this.data_pageSize));
        },
        data_currentPage(){
            return this.data_currentPage;
        },
    },
    methods: {
        handleCommand(val){
            this.data_pageSize = val;
            this.data_currentPage = 1;
        },
        handleCurrentPage(val){
            this.data_currentPage = val;
        },
        //el-table 對應事件
        handleSelect(selection, row){
            this.$emit('select',selection, row);
        },
        handleSelectAll(selection){
            this.$emit('select-all',selection);
        },
        handleSelectionChange(selection){
            this.$emit('selection-change',selection);
        },
        handleCellMouseEnter(row, column, cell, event){
            this.$emit('cell-mouse-enter',row, column, cell, event);
        },
        handleCellMouseLeave(row, column, cell, event){
            this.$emit('cell-mouse-leave',row, column, cell, event);
        },
        handleCellClick(row, column, cell, event){
            this.$emit('cell-click',row, column, cell, event);
        },
        handleRowClick(row, column, event){
            this.$emit('row-click',row, column, event);
        },
        handleHeaderClick(column, event){
            this.$emit('header-click',column, event);
        },
        clearSelection(){
            this.$refs.ref_table.clearSelection();
        },
        toggleRowSelection(row, selected){
            this.$refs.ref_table.toggleRowSelection(row, selected);
        },
        toggleAllSelection(){
            this.$refs.ref_table.toggleAllSelection();
        },
        setCurrentRow(row){
            this.$refs.ref_table.setCurrentRow(row);
        }
    }
  };
</script>

修改webpack配置文件

//webpack.config.js

const path = require('path')
const webpack = require('webpack')
function resolve(dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'vue-ly-table.min.js',  //打包輸出的名字
    library: 'lyTable',   //指定使用時的模塊名
    libraryTarget: 'umd',
    umdNamedDefine: true
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.esm.js'
    }
  },
  externals: {
    vue: {
      root: 'Vue',
      commonjs: 'vue',
      commonjs2: 'vue',
      amd: 'vue'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  performance: {
    hints: false
  },
  devtool: '#source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: false,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}

修改package.json

// 修改 package.json
{
  "name": "el-table-ly",
  "version": "1.0.0",
  "main": "dist/vue-ly-table.min.js", //對應webpack.config.js 輸出的filename
  "description": "Encapsulate the element twice, combine el-table with pagination, search and the number of rows displayed on the current page.",
  "author": "linyuan <[email protected]>",
  "private": false,  //需要發佈npm包即設爲false
  "scripts": {
   "build": "webpack --config webpack.config.js --progress --hide-modules"
  },
  ......
 }


編寫main.js

import lyTable from './lyTable.vue';
//導出模塊 以便項目引用
export default lyTable;
//註冊組件
if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.component('ly-table', lyTable);
}

項目打包

//打包  會在 dist目錄下生成vue-ly-table.min.j
npm run build 

發佈npm包

1.npm官網註冊賬號
2.回到項目目錄下  
npm login
3.npm publish 
發佈成功後就可以去npm搜索發佈的包了 注意每次發佈版本號需要不一樣

組件庫使用方法

注意:本組件依賴如下包,如果沒有請安裝
vue
   npm install vue
elementUI
   npm i element-ui -S
   
npm i el-table-ly


//xxx.vue

import lyTable from 'el-table-ly'

components: { lyTable }

<ly-table :data="dataTable"></ly-table>

使用示例:

//簡單示例
    <ly-table :data="dataTable">
        <el-table-column type="selection"></el-table-column>
        <el-table-column prop="host" label="主機" sortable></el-table-column>
        <el-table-column prop="name" label="名稱" sortable></el-table-column>
        <el-table-column prop="expression" label="表達式" sortable></el-table-column>
        <el-table-column prop="status" label="狀態" sortable></el-table-column>
        <el-table-column label="刪除">
            <el-button type="danger" size="mini" icon="el-icon-delete" circle></el-button>
        </el-table-column>
    </ly-table>

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
import lyTable from 'el-table-ly'

export default {
    name: 'mgr_manage',
    components: { lyTable },
    data() {
        return {
            dataTable:[{"host":"h25","name":"xxx25h28","expression":"111","status":"ok"},
                        {"host":"h28","name":"xxx28","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"yyy25","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"xxx25","expression":"111xxx","status":"ok"},
                        {"host":"h28","name":"xxx28","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"yyy25","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"xxx25","expression":"111xxx","status":"ok"},
                        {"host":"h28","name":"xxx28","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"yyy25","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"xxx25","expression":"111xxx","status":"ok"},
                        {"host":"h28","name":"xxx28","expression":"2222xxx","status":"warning"},
                        {"host":"h25","name":"yyy25","expression":"2222xxx","status":"warning"}]
        }
    }
}

注:沒有將el-table所有屬性和事件全部封裝,只封裝了一部分。

ly-table支持的屬性

    data,
    stripe,
    border
    height,
    max_height,
    size,
    show_header,
    highlight_current_row,
    current_row_key,
    row_class_name,
    row_style,
    cell_class_name,
    cell_style,
    row_key,
    show_summary
    
基本和el-table使用方法一致,只是需要使用v-bind   
比如 <ly-table :data="dataTable" :highlight_current_row="true"></ly-table>
    @select 
    @select-all 
    @selection-change
    @cell-mouse-enter
    @cell-mouse-leave 
    @cell-click 
    @row-click 
    @header-click
    
使用和el-table一致        
比如 <ly-table @row-click="handleRowClick"></ly-table>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章