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" :px'} : ''">

<div class="ivu-table ivu-table-small ivu-table-border ivu-table-with-fixed-top" >

<table cellspacing="0" cellpadding="0" >

<thead class="ivu-table-header">

<tr>

<th 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 >

.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 >

<!-- 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();

}

}

}