123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- <template>
- <div class="table-layout">
- <!-- 表头 -->
- <ul class="t-header" :class="{'bottom-line':showLine}">
- <!-- 复选框 -->
- <div
- v-if="selection && !isAllSelected"
- class="checkbox"
- @click="onClickSelectAll"
- >
- </div>
- <img
- v-if="isAllSelected"
- class="checkbox active"
- @click="onClickSelectAll"
- src="@/assets/images/icons/checkbox.png"
- draggable="false"
- />
- <!-- 表头各项 -->
- <li
- v-for="(headerItem,i) in header"
- :key="i"
- :style="{
- textAlign: headerItem.textAlign,
- width: headerItem.width ? headerItem.width+'px' : (100/header.length)+'%'
- }"
- >
- <!-- 名字叫header的作用域插槽,通过headerItem作用域提供表头各项 -->
- <slot :headerItem='headerItem' name='header'></slot>
- </li>
- </ul>
- <!-- 表格内容区域 -->
- <div
- class="t-con"
- v-infinite-scroll="requestMoreData"
- :infinite-scroll-disabled="!canRequestMoreData"
- ref="t-con"
- :style="`margin-right: ${hasScrollBar ? -6 : 0}px`"
- >
- <!-- 表格每一行 -->
- <ul
- class="t-item"
- :class="{'bottom-line': showLine}"
- v-for="(lineData, i) in data"
- :key="i"
- >
- <!-- 复选框 -->
- <div
- v-if="selection && !selectedIdList.some(id => id === lineData.id)"
- class="checkbox"
- @click="selectItem(lineData, i)"
- />
- <img
- v-if="selection && selectedIdList.some(id => id === lineData.id)"
- class="checkbox active"
- @click="selectItem(lineData, i)"
- src="@/assets/images/icons/checkbox.png"
- draggable="false"
- />
- <!-- 表格各项 -->
- <li
- v-for="(headerItem, j) in header"
- :key='j'
- :style="{
- textAlign: lineData.textAlign,
- width: headerItem.width ? headerItem.width + 'px' : (100 / header.length) + '%'
- }"
- :class="{
- themetxt: headerItem.fontweight,
- showWhenHover: headerItem.showWhenHover
- }"
- :title="headerItem.key === 'name' ? lineData[headerItem.key] : ''"
- >
- <!-- 名字叫tableItem的作用域插槽,通过itemData作用域把这一项表格数据向外暴露,通过lineData作用域把每一行向外暴露,通过headerItem作用域把这一项对应的表头项向外暴露 -->
- <slot
- :itemData='lineData[headerItem.key]'
- :lineData="lineData"
- :headerItem='headerItem'
- name='tableItem'
- ></slot>
- </li>
- </ul>
- </div>
- </div>
- </template>
- <script>
- import { mapState } from 'vuex'
- export default {
- props: {
- canRequestMoreData: {
- type: Boolean,
- default: true
- },
- data: {
- type: Array,
- default: Array
- },
- /**
- * 表头数据:各列名称和配置
- * fontweight: Boolean,某一列是否是关键列,会加粗显示
- * showWhenHover: Boolean,是否只在hover到这一行时才显示这一列在该行的数据
- * canclick: Booean, 是否可点击进行各种操作
- * width: Number,该列宽度
- * textAlign: css属性值
- */
- header: {
- type: Array,
- default: Array
- },
- // 是否显示复选框
- selection: {
- type: Boolean,
- defaut: false
- },
- // 是否显示每行之间的分隔线
- showLine: {
- type: Boolean,
- default: false
- }
- },
- data () {
- return {
- hasScrollBar: false,
- selectedIdList: [],
- }
- },
- computed: {
- isAllSelected() {
- if (this.data && this.data.length > 0) {
- return this.data.length === this.selectedIdList.length
- } else {
- return false
- }
- },
- },
- watch: {
- data: {
- handler(v) {
- const newSelectedIdList = []
- for (const selectedId of this.selectedIdList) {
- if (this.data.some((item) => {
- return item.id === selectedId
- })) {
- newSelectedIdList.push(selectedId)
- }
- }
- this.selectedIdList = newSelectedIdList
- },
- deep: true,
- }
- },
- methods: {
- onClickSelectAll() {
- if (this.isAllSelected) {
- this.selectedIdList = []
- } else {
- this.selectedIdList = []
- this.data.forEach(item => {
- this.selectedIdList.push(item.id)
- })
- }
- this.emitSelectionChange()
- },
- requestMoreData() {
- this.$emit('request-more-data')
- },
- emitSelectionChange () {
- let arr = this.data.filter(item => {
- return this.selectedIdList.some((selectedId) => {
- return selectedId === item.id
- })
- })
- this.$emit('selection-change', arr)
- },
- selectItem (selectedItem, i) {
- const idx = this.selectedIdList.findIndex((alreadySelectedId) => {
- return alreadySelectedId === selectedItem.id
- })
- if (idx > -1) {
- this.selectedIdList.splice(idx, 1)
- } else {
- this.selectedIdList.push(selectedItem.id)
- }
- this.emitSelectionChange()
- }
- },
- mounted () {
- const resizeObserver = new ResizeObserver((entries) => {
- if (entries[0].target.clientHeight < entries[0].target.scrollHeight) {
- this.hasScrollBar = true
- } else {
- this.hasScrollBar = false
- }
-
- })
- resizeObserver.observe(this.$refs['t-con'])
- },
- }
- </script>
- <style lang="less" scoped>
- .table-layout {
- width: 100%;
- color: #777;
- font-size: 14px;
- .checkbox {
- display: inline-block;
- margin-right: 20px;
- flex-grow: 1;
- width: 16px;
- height: 16px;
- border-radius: 2px;
- border: 1px solid #D5D8DE;
- cursor: pointer;
- user-select: none;
- &.active {
- border-radius: initial;
- border: initial;
- }
- }
- .t-header {
- display: flex;
- align-items: center;
- width: 100%;
- padding: 15px 16px 15px 16px;
- background-color: #F5F7FA;
- color: #646566;
- line-height: 19px;
- position: relative; // 为了设置z-index
- z-index: 1; // 为了避免.t-con向下滚动后覆盖本元素。因为.t-con的margin-top是负值。
- li {
- text-align: left;
- margin-right: 20px;
- flex-grow: 1;
- }
- }
- // 表格内容
- .t-con {
- padding-top: 49px; // 为了能上下滚动,overflow的值不能是visible,导致此元素是个BFC,导致绝对定位的tip在第一行无法显示在此元素区域外,只好让此元素具有padding-top以供第一行的tip显示。
- margin-top: -49px;
- height: calc(100vh - 325px); // 必须指定高度,element-ui的无限滚动指令才能生效
- overflow: auto;
- .t-item {
- display: flex;
- align-items: center;
- width: 100%;
- padding: 10px 16px 10px 16px;
- .showWhenHover {
- visibility: hidden;
- }
- &:hover {
- background: #F7F7F7;
- .showWhenHover {
- visibility: visible;
- }
- &[active-txt] {
- // 关键列,会加粗显示且有hover效果。
- >.themetxt {
- span {
- word-break: break-all;
- font-weight: bold;
- &:hover {
- color: #1FE4DC !important;
- cursor: pointer;
- }
- }
- }
- }
- }
- li {
- text-align: left;
- display: inline-block;
- margin-right: 20px;
- flex-grow: 1;
- span {
- color: #323233;
- // word-break: keep-all;
- // white-space: nowrap;
- word-break: break-all;
- white-space: normal;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- overflow: hidden;
- }
- }
- }
- .bottom-line {
- min-height: 50px;
- border-bottom: 1px solid rgba(#202020, 0.1);
- }
- }
- }
- </style>
|