vue全局組件的創建和使用,鍵盤觸發事件


1.src文件夾下的components-》table -》index.js

import MTable from './table.vue';
import MyTable from './table1.vue';

export default (Vue)=>{
Vue.component("MTable", MTable);
Vue.component(" myTable", MyTable)
}

2.src文件夾下的components-》table -》table1.vue      (組件)

 

/**
* 自定義table組件
********** columns:表頭信息 **********
* @type: index -- 序號
* checkbox -- 多選框
* date -- 日期組件
* imgUpdata -- 圖片上傳
* select -- 下拉框
* button -- 按鈕
* @width: 寬
* @title: 表頭
* @thClass: 表頭class
* @tdClass: 表列class
* @key: 字段名
* @onBlur: 失焦事件
* @onChange: change事件
* @onClick: click事件
* @tdClass: 表列class
* @option:{
optionList:下拉框的列表
optionValueKey: 綁定的value值得字段名,
optionLabelKey: [],數組最多2個label字段名
* }
* @filterable: 下拉框可搜索
* @disabled: 下拉框禁用
* @clearable: 可清空下拉框內容
* @butTitle: button名
* CheckboxGroup 是一個多選框組件
* 注:optionList必須獲取到list再賦值
***************** tableData:列表數據 **********
******* tableCheck:多選框綁定行的index ********
***********************************************
* 具體參考addAdvanceOrde.vue文件 *
***********************************************
*/
<template>
<div class="me-table">
< CheckboxGroup v-model="selections" @on-change="selectionsChange">
<div class="ivu-table-wrapper" :style="height ? {height: height + 'px'} : ''">
<div class="ivu-table ivu-table-small ivu-table-border ivu-table-with-fixed-top" style="overflow:auto;min-height:80px">
<table cellspacing="0" cellpadding="0" border="0" style="width: 100%;">
<thead class="ivu-table-header">
<tr>
<th style="white-space: normal" class="ivu-table-column-center" v-for="(item, index) in columns" :width="item.width" :class="item.thClass">
<span v-if="item.type === 'index'">#</span>
<span v-else-if="item.type === 'checkbox'">選擇</span>
<span v-else>{{item.title}}</span>
<span v-if="item.copyIcon">
<Icon type="ios-copy-outline" size="17" class="copyIcon" @click="copyFun(item.key)"></Icon>
</span>
</th>
</tr>
</thead>
<tbody class="ivu-table-tbody">
                       //tableData獲取的后台列表數據  trItem數據用於v-model綁定數據  trIndex下標哪一行
<tr class="ivu-table-row" v-for="( trItem, trIndex) in tableData">
                   //tdItem 遍歷的是 使用組件頁面的columnsEdit的數據 
<td class="ivu-table-column-center" v-for="( tdItem, tdIndex) in columns" :class="tdItem.tdClass">
<span v-if="tdItem.type === 'index'">{{trIndex + 1}}</span>
<span v-else-if="tdItem.type === 'checkbox'">
<Checkbox :label="trIndex"><span> </span></Checkbox>
</span>
<!--
-----
------
 
組件頁面中的<span  tdItem.type === 'input' && tdItem.onChange  && tdItem.onKeyUp >
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @on-blur="tdItem.onBlur(trItem, trIndex)" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
是判斷使用組件頁面的:columns="columnsEdit"中對象中的type:是否為input 並且有onChange  onKeyUp  屬性  如果有就調用span這個組件元素
調用組件的頁面
<my-table v-if="btnType[0]" :columns="columnsEdit" :tableData="tableData" :tableCheck="selects" height="650"></my-table>
this.columnsEdit = [
{
title: '工廠報價',
type: 'input',
width: '130',
key: 'factoryQuote',//和后端的key對應也就是 tableData遍歷過后的  trItem[tdItem.key]
thClass: 'headerColor',
inputClass: this.message === 1 ? 'table_input normal_1 input_color1' : this.message === 2 ? 'table_input normal_1 input_color2' : 'table_input normal_1',
placeholder: this.message === 2 ? '未查詢到核價單' : this.message === 1 ? '查詢到多條結果請確認' : '',
onBlur: this.factoryQuoteChange,
onKeyUp: this.show,
copyIcon: true
}
]
 下面這么多的span  v-if   v-else-if ....是為了判斷調用組件的頁面用哪一個span
------
------
-->
<span v-else-if="tdItem.type === 'input' && tdItem.onChange">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" @on-change="tdItem.onChange(trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onKeyUp">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onKeyUp && tdItem.onBlur">                                                                                              //鍵盤事件
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @on-blur="tdItem.onBlur(trItem, trIndex)" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onBlur">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" @on-blur="tdItem.onBlur(trItem, trIndex)" />
</span>
<!--日期-->
<span v-else-if="tdItem.type === 'date'">
  <DatePicker type="date" :value="trItem[tdItem.key]" @on-change="trItem[tdItem.key]=$event" :editable="false" clearable></DatePicker>
</span>
<span v-else-if="tdItem.type === 'input' && !tdItem.onChange && !tdItem.onBlur && !tdItem.onKeyUp">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :maxlength="tdItem.maxlength" />
</span>
<span v-else-if="tdItem.type === 'select' && tdItem.onChange">
<Select ref="select" v-model="trItem[tdItem.key]" @on-change="tdItem.onChange(trItem, trIndex)" :filterable="tdItem.filterable" :disabled="tdItem.disabled"
:clearable="tdItem.clearable">
<Option v-for="item in tdItem.option.optionList" :value="item[tdItem.option.optionValueKey]" :key="item[tdItem.option.optionKey]?item[tdItem.option.optionKey]:item[tdItem.option.optionValueKey]"
:label="tdItem.option.optionLabelKey.length === 1 ? item[tdItem.option.optionLabelKey[0]] : tdItem.option.optionLabelKey.length === 2 ?item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]:item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]+'-'+item[tdItem.option.optionLabelKey[2]]"></Option>
</Select>
</span>
<span v-else-if="tdItem.type === 'select' && !tdItem.onChange">
<Select ref="select1" v-model="trItem[tdItem.key]" :filterable="tdItem.filterable" :disabled="tdItem.disabled" :clearable="tdItem.clearable">
<Option v-for="item in tdItem.option.optionList" :value="item[tdItem.option.optionValueKey]" :key="item[tdItem.option.optionKey]?item[tdItem.option.optionKey]:item[tdItem.option.optionValueKey]"
:label="tdItem.option.optionLabelKey.length === 1 ? item[tdItem.option.optionLabelKey[0]] : tdItem.option.optionLabelKey.length === 2 ?item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]:item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]+'-'+item[tdItem.option.optionLabelKey[2]]"></Option>
</Select>
</span>
<span v-else-if="tdItem.type === 'button'">
<Button type="info" @click="tdItem.onClick(trItem, trIndex)" size="small">{{tdItem.butTitle}}</Button>
</span>
<span v-else v-html="trItem[tdItem.key]"></span>
</td>
</tr>
</tbody>
</table>
<div v-if="!tableData.length" class="no-data">暫無數據</div>
</div>
</div>
</CheckboxGroup>
</div>
</template>

<script>
import {
getImgBlobSrc
} from '@/libs/util'

export default {
//導出的tableData columns tableCheck....都是需要父頁面傳的數據,(:綁定的數據)
name: ' myTable',
props: {
// 選擇供應商之后增加明細的數據(更改供應商時可以獲取到該數據)
tableData: {
type: Array,
default () {
return []
}
},
height: {
type: String
},
// 點擊增加明細之后 彈框確定之后需要添加的table數據
columns: {
type: Array,
default () {
return []
}
},
tableCheck: {
type: Array,
default () {
return []
}
}
},
data() {
return {
modelData: [],
selections: this.tableCheck,
imgIndex: '',
imgKey: ''
}
},
mounted() {
let self = this
this.$(".ivu-table-row").hover(function () {
self.$(this).addClass('ivu-table-row-hover')
}, function () {
self.$(this).removeClass('ivu-table-row-hover')
})
},
methods: {
selectionsChange() {
this.tableCheck.splice(0, this.tableCheck.length)
this.selections.forEach(ele => {
this.tableCheck.push(ele)
})
},
copyFun(key) {
if(key === 'qualifiedQuantity'){
this.tableData.forEach(ele => {
this.$set(ele, key, ele.quantity)
ele.unqualifiedQuantity = ele.qualifiedQuantity && ele.quantity ? Number(ele.quantity) - Number(ele.qualifiedQuantity) : ''
})
return
}
if (!this.tableData[0][key] && this.tableData[0][key] != 0) {
this.$Message.warning('第一行值為空,不能復制!')
return
}
this.tableData.forEach(ele => {
this.$set(ele, key, this.tableData[0][key])
})
if (key === 'taxUnitPrice' || key === 'taxRate') {
this.tableData.forEach(ele => {
if ((ele.taxUnitPrice || ele.taxUnitPrice == 0) && (ele.taxRate || ele.taxRate == 0)) {
let unitPrice = ele.taxUnitPrice / (1 + ele.taxRate / 100)
this.$set(ele, 'unitPrice', unitPrice.toFixed(4))
}
})
}
},
uploadImg(file) {
let formData = new FormData()
formData.append('file', file)
this.$axios({
url: '/chenfan_api/file/upload',
method: 'post',
data: formData
}).then((data) => {
if (data.code === 200) {
this.$set(this.tableData[this.imgIndex], [this.imgKey], data.obj[0].id)
}
})
return false
},
getImgIndex(index, key) {
this.imgIndex = index
this.imgKey = key
},
removeImg(key, index) {
this.tableData[index][key] = ''
}
},
watch: {
tableCheck(newVal, oldVal) {
this.selections = newVal
}
}
}

</script>

<style lang="less">
.me-table {
.ivu-table-wrapper {
min-height: 80px;
}

.ivu-table-row {
td {
padding: 0 5px;
}
}

.no-data {
position: absolute;
top: 50%;
left: 50%;
font-size: 14px;
}

.demo-upload-list {
display: inline-block;
width: 70px;
height: 70px;
text-align: center;
line-height: 70px;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
margin-right: 4px;
}

.demo-upload-list img {
width: 100%;
height: 100%;
}

.demo-upload-list-cover {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .6);
}

.demo-upload-list:hover .demo-upload-list-cover {
display: block;
}

.demo-upload-list-cover i {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}

.span-img {
display: inline-block;
padding: 5px 0;
}

.ivu-checkbox-group-item {
width: 20px;
height: 20px;
overflow: hidden;
}
}

</style> 
 
3.使用組件的頁面
<Card style="margin-top: 20px;">
<!-- table1組件 -->
< my-table v-if="btnType[0]" :columns=" columnsEdit" :tableData=" tableData" :tableCheck="selects" height="650"></my-table>
</Card>
//tableData獲取的后台列表數據
 tableData:[  ],
//編輯
this. columnsEdit = [
{
type: 'index',
width: '40'
}, {
type: 'checkbox',
width: '40'
}, {
title: '品牌',
width: '100',
key: 'brandName'
},
{
title: '貨號',
width: '110',
key: 'productCode'
}, {
title: '存貨編碼',
width: '120',
key: 'inventoryCode',
thClass: 'headerColor'
}, {
title: '存貨名稱',
width: '160',
key: 'inventoryName'
}, {
title: '顏色',
width: '100',
key: 'color'
}, {
title: '尺碼',
width: '100',
key: 'size'
}, {
title: '季節',
width: '100',
key: 'season'
}, {
title: '工廠報價',
type: 'input',
width: '130',
key: 'factoryQuote',
thClass: 'headerColor',
inputClass: this.message === 1 ? 'table_input normal_1 input_color1' : this.message === 2 ? 'table_input normal_1 input_color2' : 'table_input normal_1',
placeholder: this.message === 2 ? '未查詢到核價單' : this.message === 1 ? '查詢到多條結果請確認' : '',
onBlur: this.factoryQuoteChange,
onKeyUp: this.show,//this.show是一個方法
copyIcon: true
}, {
title: '含稅單價',
type: 'input',
width: '130',
key: 'taxUnitPrice',
thClass: 'headerColor',
onBlur: this.taxUnitPriceChange,
onKeyUp: this.show,
placeholder: this.message === 2 ? '未查詢到核價單' : this.message === 1 ? '查詢到多條結果請確認' : '',
inputClass: this.message === 1 ? 'table_input normal_2 input_color1' : this.message === 2 ? 'table_input normal_2 input_color2' : 'table_input normal_2',
copyIcon: true
}, {
title: '不含稅單價',
width: '100',
key: 'unitPrice'
}, {
title: '稅率',
type: 'select',
width: '110',
key: 'taxRate',
option: {optionList: taxRateList, optionValueKey: 'key', optionLabelKey: ['key']},
thClass: 'headerColor',
onChange: this.taxRateChange,
copyIcon: true
}, {
title: '調價原因',
type: 'input',
width: '160',
key: 'remark',
thClass: 'headerColor',
onKeyUp: this.show,
inputClass: 'table_input normal_3',
copyIcon: true
},{
            title: '合同初始交期',
            type: 'date',
            width: '150',
            key: 'conStartDate',
            copyIcon: true,
            thClass: 'headerColor'
  }
]
 
 
// 刪除行
deleteTrFun () {
let _arr = []
if (!this.selects.length) this.$Message.warning('請先選擇行!')

this.tableData.forEach((ele, index) => {
console.log(this.selects, 22)
if (this.selects.indexOf(index) < 0) _arr.push(ele)
})
this.productList.splice(this.selects, 1)
console.log(this.productList, 333)
this.selects = []
this.tableData = _arr
if(!this.tableData.length){
this.btnType[1] = true
}
},
 
 
// 鍵盤觸發事件  item==組件里的$event 也就是當前元素this    trItem== row 這一條數據  trIndex===index第幾行
show (item, row, index) {
let newIndex;
// 通過ev獲取當前input的class名稱,用於后期判斷屬於哪列 
let className = item.target.offsetParent.className;
console.log(item, index);
// 每一列 inputClass中的normal_1 normal_2 normal_3 是用來判斷當前焦點在哪個input的上  用於后期上下左右鍵盤可以控制移動到某個input
if (className.indexOf('normal_1') !== -1) {
this.data = index;
this.didata = index*3;
newIndex = index*3;
} else if (className.indexOf('normal_2') !== -1) {
this.data = index;
this.didata = index*3 + 1;
newIndex = index*3 + 1;
} else if (className.indexOf('normal_3') !== -1) {
this.data = index;
this.didata = index*3 + 2;
newIndex = index*3 + 2;
}
// 獲取所有input
let inputAll = document.querySelectorAll('.table_input input');
this.iddata = inputAll;
// 向上 =38
if (item.keyCode === 38) {
newIndex -= 3;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向下 =40
if (item.keyCode === 40) {
newIndex += 3;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向左
if (item.keyCode === 37) {
newIndex -= 1;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向右
if (item.keyCode === 39) {
newIndex += 1;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM