• 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=" 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',
    '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;
    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 {
    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 {
    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',
    '40'
    }, {
    type: 'checkbox',
    '40'
    }, {
    title: '品牌',
    '100',
    key: 'brandName'
    },
    {
    title: '货号',
    '110',
    key: 'productCode'
    }, {
    title: '存货编码',
    '120',
    key: 'inventoryCode',
    thClass: 'headerColor'
    }, {
    title: '存货名称',
    '160',
    key: 'inventoryName'
    }, {
    title: '颜色',
    '100',
    key: 'color'
    }, {
    title: '尺码',
    '100',
    key: 'size'
    }, {
    title: '季节',
    '100',
    key: 'season'
    }, {
    title: '工厂报价',
    type: 'input',
    '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',
    '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: '不含税单价',
    '100',
    key: 'unitPrice'
    }, {
    title: '税率',
    type: 'select',
    '110',
    key: 'taxRate',
    option: {optionList: taxRateList, optionValueKey: 'key', optionLabelKey: ['key']},
    thClass: 'headerColor',
    onChange: this.taxRateChange,
    copyIcon: true
    }, {
    title: '调价原因',
    type: 'input',
    '160',
    key: 'remark',
    thClass: 'headerColor',
    onKeyUp: this.show,
    inputClass: 'table_input normal_3',
    copyIcon: true
    },{
                title: '合同初始交期',
                type: 'date',
                 '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();
    }
    }
    }
  • 相关阅读:
    获取最近一周
    git设置个人信息
    ajax的content-download时间过慢问题的解决与思考
    element UI table中字符太多
    git 合并代码冲突最终解决办法
    thinkphp swoole 的使用
    vue elemnet 二进制文件上传
    Python+Selenium+Chrome 笔记(2)Selenium的Hello World
    chrome 自动测试插件
    php-fpm 错误日志 与 php 错误日志的用法
  • 原文地址:https://www.cnblogs.com/wssdx/p/11114537.html
Copyright © 2020-2023  润新知