单独用到一个数据展示表,索性自己写一个锻炼下,在此记录方便后续使用。
也可进行二次封装使用,不过使用到框架肯定就不会考虑自己写了。
vue:懒省事就用他了
html+css+sass必不可少了
效果展示
大致代码块截图html+css
代码html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link
rel="stylesheet"
type="text/css"
href="https://www.jq22.com/jquery/bootstrap-3.3.4.css"
/>
<!-- iconfont在线字体图标 -->
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_3164254_1atpz15zdj.css?spm=a313x.7781069.1998910419.54&file=font_3164254_1atpz15zdj.css">
<!-- 自定义页面样式 -->
<link rel="stylesheet" href="./index.css" />
</head>
<body>
<div id="link-app" v-cloak>
<div v-if="showPopup" class="link-popup">
<div class="link-popup-content">
<div class="popup-title">链接选择器</div>
<div class="content">
<div class="content-left">
<details
@click="catChange(index,0)"
v-for="(item,index) in listData"
:key="index"
>
<summary :class="[listIndex == index && 'check-summary']">
{{item.name}}
</summary>
<ul>
<li
@click.stop="catChange(index,index1)"
v-for="(item1,index1) in item.children"
:key="index1"
:class="[catIndex == index1 && listIndex == index && 'check-li']"
>
{{item1.name}}
</li>
</ul>
</details>
</div>
<div class="content-right">
<!-- conten内容类型判断 -->
<ul v-if="contentData.type == 1">
<li v-for="(item,index) in contentData.links" :key="index">
<div class="title">{{item.name}}</div>
<div class="links">
<div
@click="clickLink(link,index,lIndex)"
v-for="(link,lIndex) in item.children"
:key="lIndex"
:class="['item', link.id == checkLink.id && 'link-check']"
>
{{link.name}}
</div>
</div>
</li>
</ul>
<!-- 单选表格 -->
<div v-if="contentData.type == 0" class="table-box">
<table>
<thead>
<tr>
<th
:style="{flex: item.flex}"
v-for="(item,i) in contentData.columns"
:key="i"
>
{{item.name}}
</th>
</tr>
</thead>
<tbody>
<tr @click="clickColumn(item,index)" v-for="(item,index) in contentData.tablist" :key="index">
<template v-for="(item1,index1) in contentData.columns">
<td v-if="item1.isCheck" :style="{flex: item1.flex}">
<div v-if="item.check" class="iconfont icon-success"></div>
<div v-else class="iconfont icon-xuanzekuangmoren"></div>
</td>
<td v-else :style="{flex: item1.flex}" :key="index1">
{{item[item1.dataIndex]}}
</td>
</template>
</tr>
</tbody>
<tfoot>
<tr>
<td style="flex: 1;display: flex; justify-content: flex-end;">
<div>
分页哦
</div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<div class="bottom">
<div class="confirm" @click="onConfirm">确定</div>
<div class="cancel" @click="onCancel">取消</div>
</div>
</div>
</div>
</div>
<script src="https://www.jq22.com/jquery/jquery-3.3.1.js"></script>
<script src="https://www.jq22.com/jquery/bootstrap-3.3.4.js"></script>
<script src="https://www.jq22.com/jquery/vue2.6.10.min.js"></script>
<script src="./index.js"></script>
</body>
</html>
js
(function() {
/**
* @param {Number} len uuid的长度
* @param {Boolean} firstU 将返回的首字母置为"u"
* @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
*/
function guid (len = 32, firstU = true, radix = null) {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
const uuid = []
radix = radix || chars.length
if (len) {
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
} else {
let r
// rfc4122标准要求返回的uuid中,某些位为固定的字符
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
uuid[14] = '4'
for (let i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
}
}
}
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
if (firstU) {
uuid.shift()
return `u${uuid.join('')}`
}
return uuid.join('')
}
var vm = new Vue({
el: '#link-app',
data: {
listData: [
{
name: '商城页面',
children: [
{
name: 'DIY页面',
type: 0, //0单选列表,1链接点击,2商品里列表选择
// table数据
tablist: [
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
{
id: 1,
name: '商城首页',
link: '/pages/index/index'
},
],
// table格式定义
columns: [
{
dataIndex: 'id',
name: '选择',
flex: 1,
isCheck: true
},
{
dataIndex: 'id',
name: 'ID',
flex: 1,
},
{
dataIndex: 'name',
name: '页面名称',
flex: 4,
},
{
dataIndex: 'link',
name: '页面路径',
flex: 4,
},
],
},
{
name: '商城链接',
type: 1, //0单选列表,1链接点击,2商品里列表选择
links: [
{
'name': "优惠卷",
children: [
{
id: guid(18),
name: '商城首页',
'link': "/pages/index/index",
'open_type': "navigate",
'params': [],
},
{
id: guid(18),
'name': "商品列表",
'link': "/other/list/list",
'open_type': "navigate",
'scene': [],
'params': [
{
'key': "cat_id",
'value': "",
'desc': "cat_id请填写在商品分类中相关分类的ID"
}
]
}
]
},
{
'name': "其他页面",
children: [
{
id: guid(18),
name: '商城首页',
'link': "/pages/index/index",
'open_type': "navigate",
'params': [],
},
{
id: guid(18),
'name': "商品列表",
'link': "/other/list/list",
'open_type': "navigate",
'scene': [],
'params': [
{
'key': "cat_id",
'value': "",
'desc': "cat_id请填写在商品分类中相关分类的ID"
}
]
}
]
}
]
},
{
name: '营销链接',
type: 1, //0单选列表,1链接点击,2商品里列表选择
links: [
{
'name': "优惠卷",
children: [
{
id: guid(18),
name: '商城首页',
'link': "/pages/index/index",
'open_type': "navigate",
'params': [],
},
{
id: guid(18),
'name': "商品列表",
'link': "/other/list/list",
'open_type': "navigate",
'scene': [],
'params': [
{
'key': "cat_id",
'value': "",
'desc': "cat_id请填写在商品分类中相关分类的ID"
}
]
}
]
}
]
},
]
}
],
listIndex: 0,
catIndex: 0,
// 选中的link
checkLink: '',
showPopup: true
},
computed: {
contentData () {
return this.listData[this.listIndex].children[this.catIndex]
},
checkTabData () {
return this.contentData.tablist?.filter(item => item.check)
},
},
created () {
console.log('created');
},
methods: {
catChange (listIndex, catIndex) {
this.listIndex = listIndex
this.catIndex = catIndex
// 清除选中~~~~~~~开始
this.checkLink = ''
let tablist = this.listData[this.listIndex].children[this.catIndex].tablist
let links = this.listData[this.listIndex].children[this.catIndex].links
if(tablist) {
tablist = tablist.map(item => {
item.check = false
return item
})
}
if(links) {
links = links.map(item => {
item.children = item.children.map(item => {
item.check = false
return item
})
return item
})
}
this.$set(this.listData[this.listIndex].children[this.catIndex],'tablist',tablist)
this.$set(this.listData[this.listIndex].children[this.catIndex],'links',links)
// 清除选中~~~~~~~~结束
},
// 选中table表item
clickColumn (item, index) {
let tablist = this.listData[this.listIndex].children[this.catIndex].tablist
tablist = tablist.map((it, i) => {
if (index === i) {
it.check = !it.check
} else {
it.check = false
}
return it
})
this.$set(this.listData[this.listIndex].children[this.catIndex],'tablist',tablist)
},
// 选中链接
clickLink (item, index, lIndex) {
let links = this.contentData.links[index]
links.children = links.children.map((it, i) => {
if (i == lIndex) {
it.check = !it.check
this.checkLink = it.check ? it : ''
} else {
it.check = false
}
return it
})
if (item.params.length) {
console.log('有额外参数');
alert('有额外参数')
}
},
onConfirm() {
console.log(this.checkLink,this.checkTabData,'选中的数据');
this.showPopup = false
},
onCancel() {
this.showPopup = false
}
}
})
})()
css
@charset "UTF-8";
body,
html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
font-size: 14px;
}
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.link-popup {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
}
.link-popup-content {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 860px;
height: 80vh;
background: #fff;
border-radius: 10px;
display: flex;
flex-direction: column;
font-size: 14px;
color: #333;
}
.link-popup .popup-title {
padding: 20px;
font-size: 18px;
font-weight: 600;
border-bottom: 1px solid #e5e5e5;
}
.link-popup .content {
height: 0;
flex: 1;
display: flex;
}
.link-popup .content-left {
padding: 20px;
padding-right: 30px;
border-right: 1px solid #e5e5e5;
max-width: 200px;
overflow-y: scroll;
}
.link-popup .content-left details {
min-width: 100px;
padding-bottom: 20px;
list-style: none;
position: relative;
}
.link-popup .content-left details::after {
content: "";
pointer-events: none;
position: absolute;
right: -14px;
top: 5px;
width: 8px;
height: 8px;
border: 2px solid #333;
border-top: 0 solid #000;
border-left: 0 solid #000;
transform: rotate(45deg);
transition: transform 0.1s ease;
}
.link-popup .content-left details summary {
cursor: pointer;
}
.link-popup .content-left details summary::-webkit-details-marker {
display: none;
}
.link-popup .content-left details .check-summary {
color: #3678f2;
font-weight: 600;
}
.link-popup .content-left details ul {
padding-top: 10px;
}
.link-popup .content-left details ul li {
cursor: pointer;
padding: 10px 20px;
}
.link-popup .content-left details ul .check-li {
background: #f4f7ff;
border-radius: 20px;
color: #3678f2;
}
.link-popup .content-left details[open]::after {
top: 8px;
transform: rotate(-135deg);
transition: transform 0.1s ease;
}
.link-popup .content-right {
flex: 1;
width: 0;
}
.link-popup .content-right > ul {
padding: 20px;
}
.link-popup .content-right > ul li .title {
margin-bottom: 18px;
font-weight: 600;
font-size: 16px;
}
.link-popup .content-right > ul li .links {
display: flex;
flex-wrap: wrap;
}
.link-popup .content-right > ul li .links .item {
cursor: pointer;
margin-bottom: 18px;
margin-right: 18px;
padding: 6px 9px;
background: #f2f4f7;
border-radius: 10px;
font-size: 14px;
}
.link-popup .content-right > ul li .links .link-check {
background: #3678f2;
color: #fff;
}
.link-popup .content-right .table-box {
height: 100%;
padding: 0 20px;
}
.link-popup .content-right table {
width: 100%;
height: 100%;
/* 设置表格的高度 */
display: flex;
flex-direction: column;
}
.link-popup .content-right table tr {
padding: 20px;
display: flex;
border-bottom: 1px solid #e5e5e5;
}
.link-popup .content-right table thead {
display: flex;
/* 将表头和表尾元素设置为表格元素 */
width: 100%;
/* 设置表头和表尾元素的宽度为 100% */
}
.link-popup .content-right table thead tr {
width: 100%;
background: rgba(229, 229, 229, 0.3);
}
.link-popup .content-right table tbody {
overflow-y: scroll;
/* 设置 tbody 元素为可滚动 */
height: 0;
/* 设置 tbody 元素的高度为 100%,以填满表格的高度 */
flex: 1;
display: flex;
flex-direction: column;
}
.link-popup .content-right table tbody tr:hover {
background: #e9f6fe;
}
.link-popup .content-right table tbody .icon-success {
font-size: 22px;
color: #f0250e;
}
.link-popup .content-right table tbody .icon-xuanzekuangmoren {
color: #999;
font-size: 22px;
}
.link-popup .bottom {
display: flex;
justify-content: flex-end;
padding: 15px 20px;
border-top: 1px solid #e5e5e5;
background: #fff;
}
.link-popup .bottom .confirm,
.link-popup .bottom .cancel {
padding: 8px 16px;
border-radius: 50px;
margin-left: 10px;
cursor: pointer;
}
.link-popup .bottom .confirm {
background: #3678f2;
color: #fff;
}
.link-popup .bottom .cancel {
box-sizing: border-box;
border: 1px solid #999;
}