vue+elementui纯表格页面(左右结构布局,构成:表格和弹窗组件、左边目录)

父页面(左右结构布局,构成:表格和弹窗组件、左边目录)

<template>
  <div style="height:100%;display:flex">
    <div class="leftshuxing">
      <left-list @cliitem="handleitem" @reload="reload" class="leftlist"></left-list>
    </div>
    <div class="rightdrig">
      <div class="gr-datagrid-notitle">
        <data-grid ref="dataGrid" @editFun="editFun" @deleteFun="deleteFun" @addFun="addFun" />
      </div>
      <gr-dialog :dialogVisible.sync="dialogVisible" :dialogOptions="dialogOptions" :dialogContentComponent="dialogContentComponent" :data="dialogData" :show="show" />
    </div>
  </div>
</template>
<script>
import dataGrid from '@/components/grid/zzqx-gn/index.vue'
import grDialog from '@/components/common/dialog/index.vue'
import leftList from '@/components/grid/zzqx-gn/leftList.vue'
import { mapState } from 'vuex'
export default {
  data() {
    return {
      dialogOptions: {},
      dialogVisible: false,
      dialogContentComponent: null,
      dialogData: {},
      show: true
    }
  },
  components: {
    dataGrid,
    grDialog,
    leftList
  },
  computed: mapState(['chooseId', 'chooseData']),

  methods: {
    reload(prame) {
      this.$refs.dataGrid.load(prame)
    },
    addFun(data) {
      this.show = true
      this.dialogVisible = true
      this.dialogOptions = {
         '700px',
        title: '增加功能',
        saveBtn: '提交'
      }
      this.dialogContentComponent = () =>
        import('@/components/dialog/zzqx-gn/add-gn.vue')
    },
    editFun() {
      if (this.chooseData.length !== 1) {
        this.$message.warning('请选择一个功能菜单后操作')
        return
      }
      this.data = this.chooseData[0]
      this.show = true
      this.dialogVisible = true
      this.dialogOptions = {
         '700px',
        title: '修改功能',
        saveBtn: '提交'
      }
      this.dialogContentComponent = () =>
        import('@/components/dialog/zzqx-gn/edit-gn.vue')
    },
    deleteFun(node, data) {
      if (!this.chooseData.length) {
        this.$message({
          message: '请选择数据进行操作',
          type: 'warning'
        })
        return
      }
      var prame = []
      this.chooseData.forEach((element) => {
        prame.push({ dxid: element.dxid })
      })
      this.$confirm('是否确定删除该数据?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
        center: true
      })
        .then(() => {
          // 删除
          this.api.post(
            this,
            'delete_gn',
            () => {
              this.$message.success('删除成功')
              this.dialogVisible = false // 关闭弹窗
              this.reload({ dxid: this.chooseId }) // 刷新数据
            },
            prame
          )
        })
        .catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          })
        })
    },
    handleitem(val) {
      this.$refs.dataGrid.load({ dxid: val.dxid })
    }
  }
}
</script>
<style lang="scss">
.general-wrap .rightdrig .gr-datagrid-notitle {
  border-bottom: none;
}
.gr-datagrid .gr-tag ::v-deep .el-collapse {
  margin: 0 22px 0 18px !important;
}
.leftshuxing {
   300px;
  background: #fff;
  margin: 3px 0 3px 5px;
}
.rightdrig {
  overflow: hidden;
  flex: 1;
  .gr-datagrid-notitle {
    height: 90%;
    height: calc(100% - 45px);
    background: #fff;
    margin: 3px 0 3px 5px;
    padding: 0 17px;
    border-bottom: solid 1px #d9d9d9;
    .gr-tag {
      line-height: 46px;
      .data-title {
        background: url('~@/assets/data-title.png') no-repeat center left;
        padding-left: 20px;
        font-size: 14px;
      }
      .el-button--primary {
        color: #fff;
        background: #409eff;
        border-color: #409eff;
        margin-left: 15px;
      }
      .el-button--primary:hover {
        background-color: rgb(193, 218, 243);
        border-color: rgb(121, 184, 248);
        color: #000;
      }
    }
  }
}
</style>

目录


<template>

  <ul :style="{height:heightstyle + 'px'}">

    <li v-for="(val, ind) of list" :key=ind @click="handlecli(val, ind)" :class="[ind == itemindex ? 'chose':null]">
      <span>{{val.mc}}</span>
    </li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      heightstyle: 500,
      list: null,
      itemindex: 0
    }
  },
  created() {
    this.heightstyle = document.body.clientHeight - 100
    this.load()
  },
  methods: {
    handlecli(val, ind) {
      this.$emit('cliitem', val)
      this.$store.state.chooseId = this.list[ind].dxid
      this.itemindex = ind
    },
    load(param) {
      this.api.get(this, 'system_left_zxt', this.result, param)
    },
    result(data) {
      this.list = data
      this.$store.state.chooseId = this.list[0].dxid
      this.handlecli(this.list[0], 0)
    }
  }
}
</script>
<style scoped lang="scss">
ul {
  padding: 10px;
  overflow-y: auto;
  box-sizing: border-box;
  margin-top: 3px;
}
li {
  padding: 2px 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
li:hover {
  color: #3083f2;
  background-color: #f5f7fa;
}
li.chose {
  color: #3083f2;
  background-color: #f5f7fa;
}
</style>

表格

<template>

  <div>
    <search @searchSubmit="searchSubmit"></search>  // 放在父页面一样
    <div class="gr-tag">
      <span class="data-title">功能管理</span>
      <el-button type="primary" size="mini" @click="addFun">增加</el-button>
      <el-button type="success" size="mini" @click="editFun">编辑</el-button>
      <el-button type="info" size="mini" @click="jiny" v-if="chooseData[0] && chooseData[0].sfjy === '1'">禁用</el-button>
      <el-button type="warning" size="mini" @click="kaiq" v-else>开启</el-button>
      <el-button type="danger" size="mini" @click="deleteFun">删除</el-button>
    </div>
    <el-table @selection-change="changeCheckbox"  ref="multipleTable" :data="tableData" stripe borders style="100%" :height="height" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" row-key="dxid">
      <el-table-column type="selection" width="42"/>
      <el-table-column prop="mc" label="功能名称" width="230"></el-table-column>
      <el-table-column prop="icon" show-overflow-tooltip  label="ICON">
        <template slot-scope="scope">
          {{scope.row.icon || '无'}}
        </template>
      </el-table-column>
      <el-table-column :formatter="changeLx" prop="lx" label="类型">
      </el-table-column>
      <el-table-column prop="sfjy" label="是否禁用">
        <template slot-scope="scope" >
          <span :style="{ color: scope.row.sfjy == 0 ? 'red' : '' }">
            {{scope.row.sfjy == 0 ? '是' : '否'}}
          </span>
        </template>
      </el-table-column>
      <el-table-column show-overflow-tooltip prop="ms" label="描述">
        <template slot-scope="scope">
          {{scope.row.ms || '无'}}
        </template>
      </el-table-column>
      <el-table-column prop="cjsj" label="创建时间" show-overflow-tooltip></el-table-column>
    </el-table>
  </div>
</template>
<script>
import index from './index.js'
export default index
</script>
<style lang="scss">
.el-checkbox__input.is-checked .el-checkbox__inner {
  background-color: #409eff;
  border-color: #409eff;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
  background-color: #409eff;
  border-color: #409eff;
}
.el-table td {
  padding: 8px 0;
}
.el-tooltip__popper {
  font-size: 14px;
  max- 50%;
}
</style>

表格逻辑

import { mapState } from 'vuex'
export default {

  data() {
    return {
      dxid: '',
      currentPage: 1,
      pagePize: 15,
      tableData: [],
      height: 500,
      total: 0,
      canshu: {},
      currentRow: []
    }
  },
  computed: mapState(['chooseId', 'chooseData']),
  created() {
    this.height = document.body.clientHeight - 110
  },
  methods: {
    changeCheckbox(val) {
      this.$store.state.chooseData = val
    },
    addFun() {
      this.$emit('addFun')
    },
    editFun() {
      this.$emit('editFun')
    },
    kaiq() {
      if (this.chooseData.length !== 1) {
        this.$message.warning('请选择一个功能菜单后操作')
        return
      }
      this.chooseData[0].sfjy = '1'
      this.api.post(this, 'edit_gn', () => {
        this.$message.success('开启成功')
      }, this.chooseData[0])
    },
    jiny() {
      if (this.chooseData.length !== 1) {
        this.$message.warning('请选择一个功能菜单后操作')
        return
      }
      this.chooseData[0].sfjy = '0'
      this.api.post(this, 'edit_gn', () => {
        this.$message.success('已禁用')
      }, this.chooseData[0])
    },
    deleteFun() {
      this.$emit('deleteFun')
    },
    load(param) {
      this.dxid = param.dxid
      this.$store.state.chooseData = []
      this.api.get(this, 'system_zxt_menu', this.result, param)
    },
    result(data) {
      this.total = data.length
      this.tableData = this.gettree(data)
    },
    gettree(data) {
      var dataList = data
      function fn(data, sjdxid) {
        var result = []
        var temp
        for (var i in data) {
          if (data[i].sjdxid === sjdxid) {
            result.push(data[i])
            temp = fn(data, data[i].dxid)
            if (temp.length > 0) {
              data[i].children = temp
            }
          }
        }
        return result
      }
      return fn(dataList, this.dxid)
    },
    changeLx(row) {
      switch (row.lx) {
        case '1':
          return '平台'
        case '2':
          return '外链'
        case '3':
          return '弹窗'
        case '4':
          return 'iframe'
        case '5':
          return 'map点位绘制'
        case '6':
          return '服务调用'
        case '7':
          return 'map线、面绘制'
        case '8':
          return 'map面绘制'
        case '9':
          return 'map ICON替换'
      }
    },
    indexMethod(index) {
      return this.pageInfo.limit * (this.pageInfo.start - 1) + 1 + index
    }
  }
}

import组件内容(分了新增和编辑操作,看情况可合并)

新增操作(两个文件差别在逻辑不同)

<template>

  <el-form :model="dataForm" label-width="110px" ref="dataForm" size="mini" :rules="rules" style="margin-right: 20px" :inline="true" label-position="right">
    <el-form-item label="功能名称" prop="mc">
      <el-input v-model="dataForm.mc" style="200px"></el-input>
    </el-form-item>
    <el-form-item label="访问路径" prop="fwlj">
      <el-input v-model="dataForm.fwlj" style="200px"></el-input>
    </el-form-item>
    <el-form-item label="是否管理" prop="mrxs">
      <el-select filterable v-model="dataForm.mrxs" placeholder="是否管理" style="200px">
        <el-option label="是" value="1"></el-option>
        <el-option label="否" value="0"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="icon" prop="icon">
      <el-input v-model="dataForm.ICON" style="200px"></el-input>
    </el-form-item>
    <el-form-item label="描述" prop="ms">
      <el-input v-model="dataForm.ms" style="200px"></el-input>
    </el-form-item>
    <el-form-item label="显示顺序" prop="xssx">
      <el-input v-model="dataForm.xssx" style="200px"></el-input>
    </el-form-item>
    <el-form-item label="类型" prop="lx">
      <el-select v-model="dataForm.lx" placeholder="选择类型" style="200px">
        <el-option v-for="li in lxlist" :key="li.id" :label="li.label" :value="li.value"></el-option>
      </el-select>
    </el-form-item>
    <!-- <el-form-item label="是否禁用" prop="sfjy">
      <el-select filterable v-model="dataForm.sfjy" placeholder="是否禁用" style="200px">
        <el-option label="是" value="1"></el-option>
        <el-option label="否" value="0"></el-option>
      </el-select>
    </el-form-item> -->
    <el-form-item label="上级对象" prop="sjdxid">
      <el-select v-model="dataForm.sjdxid" filterable placeholder="选择上级对象" style="200px">
        <el-option label="无上级菜单" value="" key=""></el-option>
        <el-option :label="item.mc" :value="item.dxid" v-for="(item,index) in funList" :key="index"></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</template>
<script>
import { mapState } from 'vuex'
export default {
  data() {
    return {
      funList: [],
      dataForm: {
        mc: '',
        fwlj: '',
        mrxs: '',
        ICON: '',
        sfjy: '0',
        lx: '',
        xssx: '',
        sjc: '{datetime}',
        cjsj: '{datetime}',
        dxid: '{uuid}',
        sjdxid: ''
      },
      lxlist: [
        { label: '平台', value: '1' },
        { label: '外链', value: '2' },
        { label: '弹窗', value: '3' },
        { label: 'iframe', value: '4' },
        { label: 'map点位绘制', value: '5' },
        { label: 'map服务调用', value: '6' },
        { label: 'map线、面绘制', value: '7' },
        { label: 'map面绘制', value: '8' },
        { label: 'map ICON替换', value: '9' }
      ],
      rules: {
        mrxs: [
          { required: true, message: '请选择是否默认显示', trigger: 'blur' }
        ],
        mc: [
          { required: true, message: '请输入功能名称', trigger: 'blur' }
        ],
        fwlj: [
          { required: true, message: '请输入访问路径', trigger: 'blur' }
        ],
        xssx: [
          { required: true, message: '请输入显示顺序', trigger: 'blur' }
        ],
        lx: [
          { required: true, message: '请输入类型', trigger: 'blur' }
        ],
        sfjy: [
          { required: true, message: '请选择是否禁用', trigger: 'blur' }
        ]
      }
    }
  },
  computed: mapState(['chooseData', 'chooseId']),
  methods: {
    result(data) {
      this.funList = data
    },
    submitForm(that) {
      this.$refs.dataForm.validate(valid => {
        if (!valid) {
          return false
        }
        this.api.post(this, 'add_gn', () => {
          this.$message.success('新增成功')
          that.modalClose() // 关闭弹窗
          that.$parent.reload({ dxid: this.chooseId })
        }, this.dataForm)
      })
    },
    resetForm() {
      this.$refs.dataForm.resetFields()
    }
  },
  created() {
    for (const key in this.data) {
      this.dataForm[key] = this.data[key]
    }
    this.api.get(this, 'gn_list', this.result)
    if (this.chooseData.length) {
      this.dataForm.sjdxid = this.chooseData[0].dxid
    } else {
      this.dataForm.sjdxid = this.chooseId
    }
  }

// ###编辑操作(不同于编辑的地方)
// methods: {

  //   submitForm(that) {
  //     this.$refs.dataForm.validate(valid => {
  //       if (!valid) {
  //         return false
  //       }
  //       this.api.post(this, 'edit_gn', () => {
  //         this.$message.success('更新成功')
  //         that.modalClose() // 关闭弹窗
  //         that.$parent.reload({ dxid: this.chooseId })
  //       }, this.dataForm)
  //     })
  //   }
  // },
  // created() {
  //   this.dataForm = Object.assign({ }, this.chooseData[0])
  //   this.api.get(this, 'gn_list', this.result)
  // 

}
</script>

查询条件

index.vue

<template>

  <el-form :inline="true" :model="formInline" size="mini" class="gr-form-search" @submit.native.prevent>
    <el-form-item label="用户名">
      <el-input clearable v-model="formInline.userName" placeholder="请输入用户名"></el-input>
    </el-form-item>
    <el-form-item label="开始时间" prop="startTime">
      <el-date-picker v-model="formInline.startTime" type="datetime" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" style="200px" placeholder="选择日期时间">
      </el-date-picker>
    </el-form-item>
    <el-form-item label="结束时间" prop="endTime">
      <el-date-picker v-model="formInline.endTime" type="datetime" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" style="200px" placeholder="选择日期时间">
      </el-date-picker>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmit">查询</el-button>
    </el-form-item>
  </el-form>
</template>
<script>
import index from './index.js'
export default index
</script>

index.js

export default {
  data() {
    return {
      formInline: {
        userName: '',
        startTime: '',
        endTime: ''

      }
    }
  },
  mounted() {
    this.onSubmit()
  },
  methods: {
    onSubmit() {
      var data = Object.assign({}, this.formInline)
      this.$emit('searchSubmit', data)
    }
  }
}

增加查询组件,父页面相对应增加方法

   load(param) {
      this.api.get(this, 'getsslist', this.result, param)
    },
    searchSubmit(data = this.canshu) {
      if (data === undefined) data = {}
      data.pageSize = this.pagePize
      data.pageNum = this.currentPage
      this.canshu = data
      this.loading = true
      this.load(data)
    },
    searchResult(data) {
      this.load(data)
    
}

弹窗组成文件含index.vue、index.js、directives.js

index.vue


<template>

  <el-dialog :title="dialogOptions.title" :visible.sync="dialogVisible" :width="dialogOptions.width" :before-close="handleClose" v-dialogDrag>

    <component ref="childFunx" :is="dialogContentComponent" :data="data" :typeSelectData="typeSelectData" :roomSelectData="roomSelectData" :day="day"></component>
    <span slot="footer" class="dialog-footer" v-if="show">
      <el-button @click="resetForm()">重置</el-button>
      <el-button type="primary" @click="submitForm()">{{dialogOptions.saveBtn}}</el-button>
      <el-button type="danger" v-if="showDel" @click="deleteDate">删除</el-button>
    </span>
  </el-dialog>
</template>
<script>
import grDialog from './index.js'
export default grDialog
</script>
<style  lang="scss">
.el-dialog {
  border-radius: 8px;
  .el-dialog__header {
    border-radius: 8px 8px 0 0;
    background: #4991f0;
    padding: 8px 15px;
    .el-dialog__headerbtn {
      top: 12px;
    }
    .el-dialog__title {
      font-size: 18px;
      color: #fff;
    }
    .el-icon-close:before {
      color: #fff;
    }
  }
  .el-dialog__body {
    padding: 25px 15px 5px 15px;
  }
  .el-dialog__footer {
    text-align: center;
    padding-top: 0;
  }
  .el-button--primary {
    color: #fff;
    background-color: #409eff;
    border-color: #409eff;
  }
  .el-button:hover {
    background-color: rgb(193, 218, 243);
    border-color: rgb(121, 184, 248);
    color: #000;
  }
}
.el-message-box {
  .el-button--primary,
  .el-button--primary:active {
    color: #fff;
    background: #409eff;
    border-color: #409eff;
  }
  .el-button:hover {
    background-color: rgb(193, 218, 243);
    border-color: rgb(121, 184, 248);
    color: #000;
  }
}
</style>

index.js

import './directives.js'

export default {
  props: {
    dialogVisible: {
      type: Boolean,
      default: false
    },
    modal: {
      type: Boolean,
      default: true
    },
    dialogOptions: {
      type: Object,
      default: { title: '', saveBtn: '保存',  '30%', isre: false }
    },
    data: { type: [Object, Array], default: () => { } },
    dialogContentComponent: { type: Function },
    show: { type: Boolean, default: true },
    showDel: { type: Boolean, default: false },
    typeSelectData: { type: Array, default: () => [] },
    roomSelectData: { type: Array, default: () => [] },
    day: { type: String, default: '' }
  },
  methods: {
    resetForm() {
      this.$refs.childFunx.resetForm()
    },
    submitForm() {
      this.$refs.childFunx.submitForm(this)
    },
    deleteDate() {
      this.$refs.childFunx.deleteDate(this)
    },
    modalClose() {
      this.$emit('update:dialogVisible', false) // 直接修改父组件的属性
    },
    reLoad() {
      this.$parent.reload()
    },
    handleClose(done) {
      this.$confirm('确认关闭?')
        .then(_ => {
          this.modalClose()
        })
        .catch(_ => { })
    }
  }
}

directives.js(一个拖动功能)

import Vue from 'vue'

Vue.directive('dialogDrag', {
  bind(el, binding, vnode, oldVnode) {
    const dialogHeaderEl = el.querySelector('.el-dialog__header')
    const dragDom = el.querySelector('.el-dialog')
    dialogHeaderEl.style.cursor = 'move'

    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)

    dialogHeaderEl.onmousedown = (e) => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft
      const disY = e.clientY - dialogHeaderEl.offsetTop

      // 获取到的值带px 正则匹配替换
      let styL, styT

      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
      if (sty.left.includes('%')) {
        styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
        styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
      } else {
        styL = +sty.left.replace(/px/g, '')
        styT = +sty.top.replace(/px/g, '')
      }

      document.onmousemove = function(e) {
        // 通过事件委托,计算移动的距离
        const l = e.clientX - disX
        const t = e.clientY - disY

        // 移动当前元素
        dragDom.style.left = `${l + styL}px`
        dragDom.style.top = `${t + styT}px`

        // 将此时的位置传出去
        // binding.value({x:e.pageX,y:e.pageY})
      }

      document.onmouseup = function(e) {
        document.onmousemove = null
        document.onmouseup = null
      }
    }
  }
})

// v-dialogDragWidth: 弹窗宽度拖大 拖小
Vue.directive('dialogDragWidth', {
  bind(el, binding, vnode, oldVnode) {
    const dragDom = binding.value.$el.querySelector('.el-dialog')

    el.onmousedown = (e) => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - el.offsetLeft

      document.onmousemove = function(e) {
        e.preventDefault() // 移动时禁用默认事件

        // 通过事件委托,计算移动的距离
        const l = e.clientX - disX
        dragDom.style.width = `${l}px`
      }

      document.onmouseup = function(e) {
        document.onmousemove = null
        document.onmouseup = null
      }
    }
  }
}
)
原文地址:https://www.cnblogs.com/wwj007/p/14385480.html