vue
- 建立本地分支并关联远程分支 git checkout -b feature-Task202
- 创建vue-cli项目遇到上下选择失效问题
- 和git创建关联
- vue中v-bind:class
- 自定义指令
- vue组件之间的通信
- vuex
- 路由传参
- 跨域
- filter过滤器
- router-view 和 keep-alive
- 全局首位钩子函数
- .v-on监听多个方法
- 在method方法里面分别写两个时事件;
- 绑定class的数组用法
- ant design vue
- form表单
- 表单下一些参数的含义以及用法
- antdesign的上传文件功能
- 下载功能
- 实现element + vue的单选功能图表的
- echarts 柱状图设置滚动条
- echarts设置提示消息的函数
- element-ui 中el-select 嵌套 tree树形控件 (多选)
- 把对象中的属性名字更换
- 根据id查对应的对象 递归实现
- element的多选table表格变成单选
- element-ui 中el-select 嵌套 tree树形控件 (单选)
- 把一个树中本地菜单和接口返回的菜单通过一个key(displayNameKey)来做对比 留下满足权限接口的前端的本地菜单
- JS删除两个数组中相同的某个对象值
- vue+element实现table表格的编辑删除保存取消
- js 递归 更改数组的key值
- JS根据子节点数据获取所有父节点
- js根据对象数组中某一属性值,合并相同项,并对某一属性累加处理
- 动态图表
- 多选下拉树,并且子节点全部选中只展示父节点
- MOCK.js总结
- element的树形table 增加 删除
- 实现把树里的某个url对象以list的形式输出出来
建立本地分支并关联远程分支 git checkout -b feature-Task202
从远程分支拉取代码 git pull develop【关联的远程源】 develop【远程指定分支】
本地推送 git push develop【关联的远程源】 feature-Task202【本地分支名】
添加远程源 git remote add origin【远程源】 xxxxxxx.git
设置远程源 git remote set-url origin URL
代码暂存 git stash
代码还原 git stash pop
代码合并(合并指定分支到当前分支) git merge dev
合并单一提交 git cherry-pick commit-id
删除分支 git branch -d dev
查看本地分支 git branch
查看本地分支和远程分支 git branch -a
创建vue-cli项目遇到上下选择失效问题
winpty vue.cmd create 项目名称
和git创建关联
git remote add origin +远程的http(建立他们之间的连接)
git push origin master 推上去
git remote -v 查看是否链接成功
vue中v-bind:class
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>(绑定一个三元运算符)
自定义指令
<div class="tab-title"
v-nav-current="{
cur,
className:'allstyle',
activeClass:'activestyle'
}"
>
//把自定义指令写在父亲的div中 这里的v-nav-current就是我们起的那个js的名字 navCurrent.js
<span class="allstyle" v-for="items,index in tj" :key='index' @click="changeNum(index)">{{items}}</span>
</div>
export default{
bind(el,binding,vnode){
console.log(el)
console.log(binding.value.className)
const _a = el.getElementsByClassName(binding.value.className)
const _b = binding.value
_a[_b.cur].className += ` ${_b.activeClass}`
},
update(el,binding,vnode){
const _a = el.getElementsByClassName(binding.value.className)
const _b = binding.value
const _oldb = binding.oldValue
_a[_oldb.cur].className = ` ${_b.className}`
_a[_b.cur].className += ` ${_b.activeClass}`
}
}
vue组件之间的通信
1.父组件向子组件传值
父组件中把父组件的值 通过props传给子组件 然后再父组件中展示出来
父组件: <zujian1 :users="users"></zujian1> 第一个users是自定义的名称 第二个是我们想要传的值
子组件 在data下面写一个
props:["users"], (当为数组或是值的时候)
props:{ //当为对象时
users:{
type:Object,
default(){
return {}
}
},
}
2.子组件像父组件传值
子组件中 首先是触发子组件的一个事件
<div v-on:click="chuanzhi">我是儿子组件</div>
然后再methods中通过this.$rmit第一个参数为自定义的一个事件 第二个是传递的值
chuanzhi(){
this.$emit("sonChanged",this.msg)
}
在父组件中接受这个值
<zujian1 v-on:sonChanged='update'></zujian1>
update就是当触发自定义事件后触发的父组件的事件
update(e){
// this.title = e;
this.mrr = e;
}
然后在遍历就可以取到子组件传过来的值
vuex
1.在page下面单独创一个store文件夹 在其下面创建一个index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
**this.$store.state.count**
state:{
name:'小明',
phone:'13366733350',
str:[]
},
// 相当于vuex的计算属性
getters:{
phoneShow:state => {
return state.phone.substring(0,3)
}
},
mutations:{
**this.$store.commit('incerent')**
strPush(state,mm){
state.str = mm
}
},
actions: {
// 异步操作
**this.$store.dispatch('incerent')**
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
modules:{
}
})
2.在组建中引用vuex中的值
import {mapState,mapGetters,mapMutations} from 'vuex'
computed:{
...mapState(['name','str']),
...mapGetters(['phoneShow']),
},
methods:{
//引入strPush修改str的值
...mapMutations(['strPush']),
jiazai(){
this.strPush([123,123,123,456,789,456,752,863,96963])
},
},
mounted() {
this.jiazai()
}
路由传参
(这是导航栏点击跳转时)
1.<div v-for="items,index in arr" :key='index'>
//跳转一个参数对应的路由 用v-bind: 也就是:绑定to
**<router-link :to="'/blog/' + index">**
<div>{{items.txt}}</div>
</router-link>
</div>
(这是点击跳转时)
1.<div v-for="items,index in arr" :key='index'>
<div @click="hhhh(index)">{{items.txt}}</div>
</div>
methods:{
hhhh(index){
**this.$router.push**({
path:'/blog/' + index
})
}
}
2.既然要跳转路由此时需要注册路由
{
//:id 接收了我们点击时传过来的值也就是 index
path: '/blog/:id',
name: 'singblod',
component: singblod
},
3.当要跳转到我们那个页面时需要创建这个页面也就是 singleblod.vue
export default{
data(){
return{
//这个就是我们通过路由传过来的参数id值
id:this.$route.params.id
}
}
}
跨域
在proxyTable中配置一下
'/v1': {
target: 'http://*********.com', // 接口的域名
// secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
pathRewrite: {
// '^/v1': 'app.php' //像接口 http://localhost:8081/v1?c=cross&a=gdzh_list 最终请求时是这样的 都会有一个叫做v1的 我这里把他重写成了app.php
'^/v1': ''
}
}
配置完成之后切记要重启项目!!!
filter过滤器
在src下面创建一个filter。js
export default {
setOrders(status){
switch(status){
case 1:
return '待付款';
case 2:
return '待发货';
case 3:
return '待收货';
case 4:
return '待评价';
}
},
setOrdersStyle(status){
switch(status){
case '待付款':
return 'red';
case '待发货':
return 'blue';
case '待收货':
return 'yellow';
case '待评价':
return 'orange';
}
},
}
在组件中引用这个js然后在
import filterMy from '../filter/filter.js'
data(){},
filters:filterMy,
methods:{}
在div中 //每个 | 前面的都是我们filter下的参数
<td :class="items.status | setOrders | setOrdersStyle">{{items.status | setOrders}}</td>
router-view 和 keep-alive
匹配最近的router-link
我在app.vue中写了一个 全局的
<router-link to="/">组件1</router-link>
<router-link to="/zujian1">组件2</router-link>
<router-view /> //他会把组件一盒组件二渲染出来
我在组件二下面又写了两个切换的组件他是组件二的两个儿子组件
<router-link to="/zujian1/tongxin">组件3</router-link>
<router-link to="/zujian1/tongxin1">组件4</router-link>
//当需要缓存时 我们可以给router-view加一个keep-alive
//当keepAlive为true时被keep-alive包裹着的是需要被缓存的 反之亦然
<keep-alive>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
路由的配置
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path: '/zujian1',
name: 'Zujian1',
component: zujian1,
children: [
{
path: 'tongxin',
component: tongxin,
meta: {
keepAlive: true // 需要缓存
}
},
{
path: 'tongxin1',
component: tongxin1,
meta: {
keepAlive: false // 需要缓存
}
}
]
},
]
全局首位钩子函数
vue-router
他里面的两个钩子函数 beforeEach afterEach
用法 在 main.js里直接写(适应于如果还没有登陆时 我们要是访问权限的路由需要登录才可)
里面有三个参数 to(到哪个组件) from(离开的路由) next(是一个方法)
router.beforeEach((to,from,next) => {
var login = false;
//若果没登录还要访问我们的权限组件的路由时
// if(!login && to.path == '/zujian1'){
// next('/');
// }
//若果没登录还要访问我们的权限组件的路由时 并且在访问时退出了登录 此时需要退出我们的权限页面时
if(!login && to.matched.some((item) => {
return item.path == '/zujian1'
})){
next('/');
}
else{
next();
}
})
.v-on监听多个方法
<a style="cursor:default" v-on='{click:DoSomething,mouseleave:MouseLeave}'>doSomething</a>
在method方法里面分别写两个时事件;
<button @click="a(),b()">点我ab</button>
绑定class的数组用法
1.对象方法v-bind:class="{'orange':isRipe, 'green':isNotRipe}”
2.数组方法v-bind:class="[class1,class2]"
3.行内v-bind:style="{color:color,fontSize:fontSize+'px'}”
ant design vue
form表单
// :form="pwdform"
<a-form abelAlign="right" :form="pwdform" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
<a-form-item label="新密码">
<a-input-password
allowClear
placeholder="请输入新密码"
v-decorator="[
'password',
{
rules: [
//设置表单域的值
{initialValue:''},
{ required: true, message: '密码不能为空' },
{ max: 16, min: 1, message: '密码长度应在4至16位之间' },
{ pattern: '^.*(?=.*\\d)(?=.*[A-Z]{1,})(?=.*[a-z]{1,}).*$', message: '密码必须包含大小写字母和数字' },
//自定义校验
{ validator: this.chongzhimima },
],
},
]"
/>
</a-form-item>
return{
pwdform: this.$form.createForm(this, { password: '' }),
}
//用来获取表单的所有值
const formData = this.pwdform.getFieldsValue()
//用来进行所有表单的验证 只有通过才能执行里面的操作
this.pwdform.validateFields((err, values) => {
if (!err) {
resetPassword({ id: this.selectRow.id, password: formData.password })
.then((res) => {
if (res.status === '00000') {
this.$message.success('重置成功')
} else {
this.$message.success(res.message)
}
this.pwdform.resetFields()
this.visible = false
})
.catch((rres) => {
console.log(rres)
this.$message.error('重置失败')
})
}
})
//相当于v-model this.form.setFieldsValue设置值
this.$nextTick(() => {
//为表单设置值
this.form.setFieldsValue({
displayName: record.displayName,
username: record.username,
phoneNo: record.phoneNo,
passwordExpiryDate: record.passwordExpiryDate == null ? null : moment(record.passwordExpiryDate),
expiryDate: record.expiryDate == null ? null : moment(record.expiryDate),
orgId: [...new Set(this.getParentId(data, record.orgId, []))],
serialIndex: record.serialIndex,
accountState: record.accountState + '',
})
})
表单下一些参数的含义以及用法
labelCol 是label所占的百分比,wrapperCol 是label后面的内容所占的百分比
labelCol: { // 24格栅格系统,label所占为 a
xxl: 5, // ≥1600px 响应式栅格
xl: 8, // ≥1200px 响应式栅格
lg: 10, // ≥992px 响应式栅格
md: 12 // ≥768px 响应式栅格
},
wrapperCol: { // 24格栅格系统,label后面内容所占为 24-a
xxl: 19,
xl: 16,
lg: 14,
md: 12
},
antdesign的上传文件功能
<a-upload
name="file"
:multiple="true"
:customRequrst = 'uploadFnc'
:headers="headers"
@change="handleChange"
>
<a-button> <a-icon type="upload" /> Click to Upload </a-button>
</a-upload>
uploadFnc(file){
console.log(file)
const fileName = file.file.name
const formData = new FormData()
formData.append("file",file.file,fileName)
//uploads 是我写的接口
uploads(formData).then((res) =>{
file.onsuccess(res.data,file)})
},
下载功能
export function exportData (param) {
return axios({
url: `/detect/sample/exportSample`,
data: param,
method: 'post',
responseType: 'blob'
})
}
downloadFile1 () {
var that = this
exportData(
{ client: that.queryParam.client,
entrustNo: that.queryParam.entrustNo,
name: that.queryParam.name,
testSampleNo: that.queryParam.testSampleNo
}
).then(res => {
const blob = new Blob([res])
//这里的名字是后台传值过来的
const fileName = '样品清单.xls'
const link = document.createElement('a')
link.download = fileName
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(link.href)
document.body.removeChild(link)
})
},
实现element + vue的单选功能图表的
<el-table ref="multipleTable" :data="dialogTables" @select-all="dialogCheck" @select="dialogCheck" @selection-change="dialogCheckChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column property="ANAME" label="模块名称"></el-table-column>
</el-table>
data(){
selectioned:''
}
/**
* 单选操作,全选按钮失效操作
*/
dialogCheck: function(selection, row) {
this.$refs.multipleTable.clearSelection()
if (selection.length === 0) { // 判断selection是否有值存在
return
}
if (row) {
this.selectioned = row
this.$refs.multipleTable.toggleRowSelection(row, true)
}
},
/**
* 取消单选的checkbox
*/
dialogCheckChange(row) {
if (row.length === 0) {
this.selectioned = null
}
}
echarts 柱状图设置滚动条
dataZoom: [
//1.横向使用滚动条
{
type: 'slider',//有单独的滑动条,用户在滑动条上进行缩放或漫游。inside是直接可以是在内部拖动显示
show: true,//是否显示 组件。如果设置为 false,不会显示,但是数据过滤的功能还存在。
start: 0,//数据窗口范围的起始百分比0-100
end: 50,//数据窗口范围的结束百分比0-100
xAxisIndex: [0],// 此处表示控制第一个xAxis,设置 dataZoom-slider 组件控制的 x轴 可是已数组[0,2]表示控制第一,三个;xAxisIndex: 2 ,表示控制第二个。yAxisIndex属性同理
bottom: -10 //距离底部的距离
},
//2.在内部可以横向拖动
{
type: 'inside',// 内置于坐标系中
start: 0,
end: 30,
xAxisIndex: [0]
},
//3.纵向使用滚动条
{
type: 'slider',
show: true,
yAxisIndex: [0],//设置组件控制的y轴
left: '93%',//距离左侧的距离 可以使百分比,也可以是像素 left: '30'(30像素)
start: 29,
end: 36
},
//4.在内部可以纵向拖动
{
type: 'inside',
yAxisIndex: [0],
start: 29,
end: 36
}]
echarts设置提示消息的函数
formatter: function(params, i) {
if(params.data.label !== undefined){
if(params.data.label.position === 'left' || params.data.label.position === 'right' ){
return
}
}else{
return `<span style='color:rgba(0, 255, 252, 1)'>${params.data.target} </span>的
<span style="color:rgba(0, 255, 252, 1)">${params.data.source}</span> 碳排放总量为
<span style="color:rgba(0, 255, 252, 1)">${params.data.value.toFixed(2)}</span>`
},
}
element-ui 中el-select 嵌套 tree树形控件 (多选)
<el-select v-model="mineStatus" placeholder="请选择" multiple collapse-tags @change="selectChange">
<el-option :value="mineStatusValue" :disabled="true" style="height: auto; width: 100%;background: white">/
<el-tree :data="data" show-checkbox node-key="id" ref="tree" highlight-current :props="defaultProps" @check-change="handleCheckChange"></el-tree>
</el-option>
</el-select>
js部分
<script>
export default {
data() {
return {
mineStatus: "",
mineStatusValue: [],
data: [
{
id: 1,
label: "一级 1",
children: [
{
id: 4,
label: "二级 1-1"
}
]
},
{
id: 2,
label: "一级 2",
children: [
{
id: 5,
label: "二级 2-1"
},
{
id: 6,
label: "二级 2-2"
}
]
},
{
id: 3,
label: "一级 3",
children: [
{
id: 7,
label: "二级 3-1"
},
{
id: 8,
label: "二级 3-2"
}
]
}
],
defaultProps: {
children: "children",
label: "label"
}
};
},
methods: {
//select框值改变时候触发的事件
selectChange(e){
var arrNew = [];
var dataLength = this.mineStatusValue.length;
var eleng = e.length;
for(let i = 0; i< dataLength ;i++){
for(let j = 0; j < eleng; j++){
if(e[j] === this.mineStatusValue[i].label){
arrNew.push(this.mineStatusValue[i])
}
}
}
this.$refs.tree.setCheckedNodes(arrNew);//设置勾选的值
},
handleCheckChange() {
let res = this.$refs.tree.getCheckedNodes(true, true); //这里两个true,1. 是否只是叶子节点 2. 是否包含半选节点(就是使得选择的时候不包含父节点)
let arrLabel = [];
let arr = [];
res.forEach(item => {
arrLabel.push(item.label);
arr.push(item);
});
this.mineStatusValue = arr;
this.mineStatus = arrLabel;
console.log('arr:'+JSON.stringify(arr))
console.log('arrLabel:'+arrLabel)
}
}
};
</script>>
把对象中的属性名字更换
JSON.parse(JSON.stringify(arrayData).replace(/oldName/g, 'newName'))
//arrayData为数组,oldName为json内现有的,newName为想要更改的名字
根据id查对应的对象 递归实现
this.editTree = this.digui(this.dataTree, data.parent_id)
console.log(this.editTree)
digui (data, id) {
for (let i = 0; i < data.length; i++) {
let item = data[i]
if (item.object_id === id) {
return item
} else {
// item.children 不等于 undefined && item.children.length 大于 0 时
if (item.children && item.children.length > 0) {
let res = this.digui(item.children, id)
if (res) {
return res
}
}
}
}
},
element的多选table表格变成单选
<t-table
ref="multipleTable"
:data="paramDataPg"
:row-key="rowKey"
highlight-current-row
line
size="sm"
@selection-change="handleSelectionChange" @row-click="handleRowClick">
<t-table-column :reserve-selection="true" width="60" type="selection"></t-table-column>
<template v-for="(item, index) in columnsOther">
<t-table-column :prop="item.prop" :label="item.label" :key="index" show-overflow-tooltip></t-table-column>
</template>
</t-table>
<div class="paginationCss">
<t-pager :current.sync="tableDataOtherPage.current" :sizer-range="[10,30,60]" :page-size.sync="tableDataOtherPage.pageSize" :total="tableDataOtherPage.total" size="sm" show-elevator style="float: right;margin-top: 10px;" show-sizer @on-size-change="handleSizeChangeOther" @on-change="handleCurrentChangeOther">
</t-pager>
</div>
//data
paramDataPg: [
{users: '1', name: '张三'},
{users: '2', name: '李四'},
{users: '3', name: '王五'},
{users: '4', name: '学3'},
{users: '5', name: '阿达'},
{users: '6', name: '而且额'},
{users: '7', name: '沙发'}
],
multipleTable: [],
columnsOther: [
{ label: '用户名', prop: 'users' },
{ label: '昵称', prop: 'name' }
],
// methods
handleSelectionChange (val) {
if (val.length > 1) {
this.$refs.multipleTable.clearSelection()
this.$refs.multipleTable.toggleRowSelection(val.pop())
} else {
var obj = val.pop()
if (obj) {
this.multipleTable[0] = obj
this.pgInform.pgPeople = this.multipleTable[0].name
this.pgInform.pgPeopleId = this.multipleTable[0].users
// this.multipleTable 就是单选过后的对象
}
}
},
handleRowClick(row) {
this.$refs.multipleTable.toggleRowSelection(row)
},
rowKey (row) {
return row.users
},
element-ui 中el-select 嵌套 tree树形控件 (单选)
<el-select v-model="zhuanDanInform.parentNodeLabel" style="width: 100%;" placeholder="请选择转单人员">
<el-option :value="zhuanDanInform.parentNodeLabelid " style="height: auto; width: 100%;background: white">
<el-tree
ref="treeFormZhuandan"
:data="dataTreeZhuandanTrue"
node-key="object_id"
show-checkbox
check-strictly
default-expand-all
@check-change="handleNodeClick">
<span slot-scope="{ data }" class="custom-tree-node">
<span>{{ data.object_name }}</span>
</span>
</el-tree>
</el-option>
</el-select>
//data
zhuanDanInform: {
parentNodeLabel: '',
parentNodeLabelid: '',
content: ''
},
dataTreeZhuandan: [{
object_id: '1',
object_name: '转单1',
children: [
{
object_id: '2',
object_name: '转单2'
},
{
object_id: '3',
object_name: '转单3'
}
]
},
{
object_id: '4',
object_name: '转单4',
children: [
{
object_id: '5',
object_name: '转单5'
},
{
object_id: '6',
object_name: '转单6'
}
]
}]
dataTreeZhuandanTrue: [],
//mounted
// 为了让其不选择有children的父集
this.defaultShow(this.dataTreeZhuandan)
this.dataTreeZhuandanTrue = this.dataTreeZhuandan
//methods
handleNodeClick (data, checked) {
if (checked === true) {
this.checkedId = data.object_id
this.$refs.treeFormZhuandan.setCheckedKeys([data.object_id])
this.zhuanDanInform.parentNodeLabel = this.$refs.treeFormZhuandan.getCheckedNodes()[0].object_name
// 用id传参数 用label显示东西
this.zhuanDanInform.parentNodeLabelid = this.$refs.treeFormZhuandan.getCheckedNodes()[0].object_id
} else {
if (this.checkedId === data.object_id) {
this.$refs.treeFormZhuandan.setCheckedKeys([data.object_id])
}
}
},
defaultShow (arr) {
arr.map(item => {
item.disabled = false
if (item.children) {
item.disabled = true
this.defaultShow(item.children)
}
})
}
把一个树中本地菜单和接口返回的菜单通过一个key(displayNameKey)来做对比 留下满足权限接口的前端的本地菜单
this.jisuo(this.data[0]) // 这是接口返回的菜单
this.newViews = JSON.parse(JSON.stringify(views)) // 这是本地存储的菜单
this.IterationDelateMenuChildren(this.newViews)
var arrs = [] // 消除为empty的数组
this.newViews.map(item => { // 消除为empty的数组
arrs.push(item) // 消除为empty的数组
}) // 消除为empty的数组
this.shuxing(arrs) // 去除这个single属性
jisuo (previousList) {
previousList.map(item => {
this.digui(this.newViews, item)
if (item.children) {
this.jisuo(item.children)
}
})
},
digui(data, id) {
for (let i = 0; i < data.length; i++) {
let item = data[i]
if (item.displayNameKey === id.resources_name) {
item.single = true
item.idSelf = id.resources_id
} else {
if (item.children && item.children.length > 0) {
this.digui(item.children, id)
}
}
}
},
// 去除single不为true的 因为我把所有name能够匹配的到的 新加了一个属性为true
IterationDelateMenuChildren (arr) {
if (arr) {
for (let i in arr) {
if (arr[i].single && arr[i].children) {
this.IterationDelateMenuChildren(arr[i].children)
} else if (!arr[i].single) {
delete arr[i]
}
}
}
},
shuxing (tableData) {
tableData.map(item => {
delete item.single
if (item.children) {
this.shuxing(item.children)
}
})
},
JS删除两个数组中相同的某个对象值
var arr1=[{id:1},{id:2},{id:3},{id:4},{id:5}]
var arr2=[{id:1},{id:2},{id:3}]
var set=arr2.map(item=>item.id)
console.log(set)
var resArr=arr1.filter(item=>!set.includes(item.id))
console.log(resArr)
vue+element实现table表格的编辑删除保存取消
<el-button
type="primary"
icon="plus-outline"
@click="xinzengs"
>新增</el-button>
<el-tabs>
<el-tab-pane label="参数名">
<!-- 参数名的新增编辑删除保存取消 -->
<el-table
:data="tableData"
size="small"
line
all-show-tooltip-when-overflow
highlight-current-row>
<el-table-column
:index="indexMethod"
type="index"
label="序号"
width="60"
></el-table-column>
<el-table-column prop="codes" label="参数编码">
<template slot-scope="scope">
<el-input size="small" type="text" v-model="scope.row.codes" v-show="scope.row.iseditor" />
<span v-show="!scope.row.iseditor">{{scope.row.codes}}</span>
</template>
</el-table-column>
<el-table-column prop="names" label="参数名称">
<template slot-scope="scope">
<el-input size="small" type="text" v-model="scope.row.names" v-show="scope.row.iseditor" />
<span v-show="!scope.row.iseditor">{{scope.row.names}}</span>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<a
v-show="!scope.row.iseditor"
href="javascript:void(0)"
size="small"
@click="edit(scope.row)"
style="color: #147bd1"
>编辑</a
>
<span v-show="!scope.row.iseditor" style="color: #bbbec1"> | </span>
<a
v-show="!scope.row.iseditor"
href="javascript:void(0)"
size="small"
@click="deletes()"
style="color: #ff5f5f"
>删除</a
>
<a
v-show="scope.row.iseditor"
href="javascript:void(0)"
size="small"
style="color: #147bd1"
@click="save(scope.row)"
>保存</a
>
<span v-show="scope.row.iseditor" style="color: #bbbec1"> | </span>
<a
v-show="scope.row.iseditor"
href="javascript:void(0)"
size="small"
style="color: #ff5f5f"
@click="() => cancels(scope.row, scope.$index)"
>取消</a
>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
export default ({
data () {
return {
tableData: [
{
codes: "aaa",
names: "testcode",
iseditor: false
},
{
codes: "bbb",
names: "testcode",
iseditor: false
},
{
codes: "ccc",
names: "testcode",
iseditor: false
}
],
arr: {}
}
},
methods: {
edit(row) {
row.iseditor = true;
this.arr = {}
this.arr = JSON.parse(JSON.stringify(row))
},
save(row) {
if (row.codes && row.names) {
row.iseditor = false;
} else {
this.$message.warning("参数编码或参数名称不能为空!");
}
},
deletes () {
this.$confirm("确认删除该参数吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {});
},
cancels (row, index) {
if (index === (this.tableData.length - 1)) {
if (Object.keys(this.arr).length) {
row.codes = this.arr.codes
row.names = this.arr.names
row.iseditor = false;
} else {
this.tableData.splice(index, 1);
}
} else {
row.codes = this.arr.codes
row.names = this.arr.names
row.iseditor = false;
}
},
xinzengs () {
let single = true
this.tableData.map(item => {
if (!item.codes || !item.names) {
this.$message.warning("请先保存参数,在进行新增!");
single = false
}
})
if (single) {
this.arr = {}
this.tableData.push({
codes: '',
names: '',
iseditor: true
})
}
}
}
})
js 递归 更改数组的key值
var tree=[
{
tename:'一级',
teList:[
{
tename:'二级',
teList:[
{
tename:'三级',
teList:[
]
}
]
},
]
},
{
tename:'一yi级',
teList:[
{
tename:'二级',
teList:[
{
tename:'三级',
teList:[
]
}
]
},
]
}
]
var key = 'children'
var keyname = 'name'
function parseJson(arr) {
arr = arr.slice()
function toParse(arr) {
arr.forEach(function (item) {
if (item.teList && Array.isArray(item.teList)) {
item[key] = item.teList
item[keyname] = item.tename
toParse(item[key])
}
delete item.teList
delete item.tename
})
return arr
}
return toParse(arr)
}
console.log(parseJson(tree))
JS根据子节点数据获取所有父节点
const cities = [
{
"value": "13",
"text": "河北省",
"children": [
{
"value": "1306",
"text": "保定市",
"children": [
{
"value": "130602",
"text": "竞秀区"
},
{
"value": "130606",
"text": "莲池区"
},
{
"value": "130607",
"text": "满城区"
},
{
"value": "130608",
"text": "清苑区"
},
{
"value": "130609",
"text": "徐水区"
},
{
"value": "130628",
"text": "高阳县"
},
{
"value": "130636",
"text": "顺平县"
}
]
}
]
}
]
function treeFindPath(tree, func, field = "", path = []) {
if (!tree) return []
for (const data of tree) {
field === "" ? path.push(data) : path.push(data[field]);
if (func(data)) return path
if (data.children) {
const findChildren = treeFindPath(data.children, func, field, path)
if (findChildren.length) return findChildren
}
path.pop()
}
return []
const cId = "130628";
let arr = this.treeFindPath(cities, data => data.value === cId, "text");
console.log(arr);
// ["河北省", "保定市", "高阳县"]
// 注意在递归时在vue中函数加this (treeFindPath这个函数不用动,只修改传参就好)
js根据对象数组中某一属性值,合并相同项,并对某一属性累加处理
let data = [{ code: 1001, name: '苹果', sl: 11 },
{ code: 1001, name: '苹果', sl: 11 },
{ code: 1001, name: '苹果', sl: 11 },
{ code: 1001, name: '苹果', sl: 11 },
{ code: 1002, name: '西瓜', sl: 11 },
{ code: 1002, name: '西瓜', sl: 15 },
{ code: 1003, name: '梨', sl: 15 },
{ code: 1003, name: '梨', sl: 15 }]
第一种:根据对象key的唯一性,累加sl值
let item = {}
for (let i = 0; i < data.length; i++) {
item[data[i].code] = ~~item[data[i].code] + data[i].sl
}
console.log(item)
// 结果: {1001: 44, 1002: 26, 1003: 30}
第二种:根据reduce遍历累加,得到数组
let newArray = data.reduce((total, cur, index) => {
let hasValue = total.findIndex(current => { return current.code === cur.code})
hasValue === -1 && total.push(cur)
hasValue !== -1 && (total[hasValue].sl = total[hasValue].sl + cur.sl)
return total
}, [])
console.log(newArray)
// 结果:
[{code: 1001, name: "苹果", sl: 44},
{code: 1002, name: "西瓜", sl: 26},
{code: 1003, name: "梨", sl: 30}]
动态图表
<template>
<div>
<div id="main"></div>
</div>
</template>
<script>
// import moment from "moment";
export default {
data () {
return {}
},
mounted () {
this.getZXT()
},
methods: {
getZXT () {
var myChart = this.$echarts.init(document.getElementById("main"));
var KSMC = [100, 82, 80, 70, 65, 66, 60, 54, 50, 42];
var option = {
color: ["#3398DB"],
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: [
{
type: "category",
data: [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
],
axisLabel: {
interval: 0,
fontSize: 18,
formatter: function (value) {//横坐标数据竖着显示
var str = value.split("");
return str.join("\n");
},
},
},
],
dataZoom: [
//滑动条
{
xAxisIndex: 0, //这里是从X轴的0刻度开始
show: false, //是否显示滑动条,不影响使用
type: "slider", // 这个 dataZoom 组件是 slider 型 dataZoom 组件
startValue: 0, // 从头开始。
endValue: 6, // 一次性展示6个。
},
],
yAxis: [
{
type: "value",
inverse: false, //是否是反向坐标轴
},
],
series: [
{
name: "直接访问",
type: "line",
barWidth: "60%",
data: KSMC,
smooth: true,
areaStyle: {},
},
],
};
myChart.setOption(option);
setInterval(function () {
// 每次向后滚动一个,最后一个从头开始。
// console.log(option.dataZoom[0].endValue);
// console.log("---"+KSMC.length);
if (option.dataZoom[0].endValue == KSMC.length) {
option.dataZoom[0].endValue = 6;
option.dataZoom[0].startValue = 0;
} else {
option.dataZoom[0].endValue = option.dataZoom[0].endValue + 1;
option.dataZoom[0].startValue = option.dataZoom[0].startValue + 1;
}
myChart.setOption(option);
}, 2000);
},
},
};
</script>
<style scoped>
#main {
width: 800px;
height: 600px;
}
</style>
多选下拉树,并且子节点全部选中只展示父节点
<template>
<el-tooltip
:content="valueTranslate.toString()"
placement="top"
effect="light"
>
<el-select
class="main-select-tree"
ref="selectTree"
v-model="value"
multiple
@change="selectchange"
collapse-tags
>
<template slot="prefix">
{{ (options1.find((item) => item.value === value) || {}).label }}
</template>
<el-option
v-for="(item, index) in options1"
:key="index"
:label="item.label"
:value="item.value"
style="display: none"
/>
<el-tree
class="main-select-el-tree"
ref="selecteltree"
:data="datas"
node-key="id"
highlight-current
show-checkbox
:props="defaultProps"
@check-change="handleNodeClick"
:current-node-key="value"
:expand-on-click-node="expandOnClickNode"
default-expand-all
/>
</el-select>
</el-tooltip>
</template>
<script>
export default {
data () {
return {
value: [5, 11],
expandOnClickNode: true,
datas: [
{
id: 1,
label: '云南',
children: [{
id: 2,
label: '昆明',
children: []
}]
},
{
id: 3,
label: '五华区',
children: [{
id: 8,
label: '北辰小区',
children: [{
id: 9,
label: '我是你吧'
}]
}]
},
{
id: 4,
label: '盘龙区'
},
{
id: 5,
label: '湖南',
children: [
{ id: 6, label: '长沙' },
{ id: 7, label: '永州' }
]
},
{
id: 10,
label: '10区'
},
{
id: 11,
label: '11区'
}],
defaultProps: {
children: 'children',
label: 'label'
},
options1: [],
valueTranslate: []
}
},
mounted () {
this.options1 = []
this.formatData(this.datas)
this.selectchange()
},
methods: {
// 处理value转成中文
changeValue () {
this.valueTranslate = []
this.options1.map(item => {
this.value.map(item1 => {
if (item.value == item1) {
this.valueTranslate.push(item.label)
}
})
})
console.log(this.valueTranslate)
},
// 回调处理数据
formatData (data) {
data.forEach((item, key) => {
this.options1.push({ label: item.label, value: item.id });
if (item.children && item.children.length) {
item.children.forEach((items, keys) => {
this.options1.push({ label: items.label, value: items.id });
})
this.formatData(item.children)
}
});
},
handleNodeClick (node) {
this.value = []
// this.$refs.selecteltree.getCheckedNodes().map(item => {
// if (item.children) {
// this.value.push(item.id)
// }
// })
let newArr = this.getSimpleCheckedNodes(this.$refs.selecteltree.store)
console.log(newArr)
newArr.map(item => {
this.value.push(item.id)
})
this.changeValue()
},
// 子节点全部选中只输出父节点
getSimpleCheckedNodes (store) {
const checkedNodes = [];
const traverse = function (node) {
const childNodes = node.root ? node.root.childNodes : node.childNodes;
childNodes.forEach(child => {
if (child.checked) {
checkedNodes.push(child.data);
}
if (child.indeterminate) {
traverse(child);
}
});
};
traverse(store)
return checkedNodes;
},
selectchange () {
this.$refs.selecteltree.setCheckedKeys(this.value);
this.changeValue()
},
}
}
</script>
<style lang="scss">
.main-select-tree {
min-width: 300px;
// height: 40px;
// max-width: 500px;
// .el-select__tags {
// max-width: 500px !important;
// }
}
.main-select-el-tree .el-tree-node .is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
.main-select-el-tree .el-tree-node.is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
.el-tag.el-tag--info {
background-color: #bbd5f0;
border-color: #cde0f4;
color: #184794;
height: 30px;
}
.el-tag.el-tag--info .el-tag__close {
color: #184794;
}
.el-select .el-tag__close.el-icon-close {
background: none;
}
</style>
MOCK.js总结
开始 & 安装
# 安装
npm install mockjs
// 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素
'list|1-10': [{
// 属性 id 是一个自增数,起始值为 1,每次增 1
'id|+1': 1
}]
})
// 输出结果
console.log(JSON.stringify(data, null, 4))
element的树形table 增加 删除
<template>
<div>
<el-button type="primary" @click="addBigParent">增加子集</el-button>
<el-table
:data="tableData"
style="width: 100%; margin-bottom: 20px"
row-key="id"
border
default-expand-all
line
all-show-tooltip-when-overflow
highlight-current-row
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:row-class-name="rowClassName"
>
<el-table-column prop="index" label="序号" width="150"></el-table-column>
<el-table-column prop="date" label="检查内容" sortable width="180">
</el-table-column>
<el-table-column prop="name" label="标准值" sortable width="180">
</el-table-column>
<el-table-column prop="address" label="是否拍照"> </el-table-column>
<el-table-column prop="operate" label="操作" fixed="right">
<template slot-scope="scope">
<a
href="javascript:void(0);"
style="color: #147bd1"
@click="addBig(scope.row, scope.$index)"
>增加子集</a
>
<span style="color: #bbbec1"> | </span>
<a
href="javascript:void(0);"
class="delete"
@click="remove(scope.row, scope.$index)"
>删除</a
>
</template>
</el-table-column>
<div slot="empty">
<emptyContent></emptyContent>
</div>
</el-table>
</div>
</template>
<script>
export default {
data () {
return {
tableData: [{
id: 1,
date: '工具检查',
name: '',
address: '',
children: [{
id: 2,
date: '工具检查',
name: '',
address: '',
children: [{
id: 3,
date: '工具检查1',
name: '100',
address: '是'
}]
}, {
id: 4,
date: '工具检查2',
name: '100',
address: '是'
}]
}, {
id: 5,
date: '电梯、爬梯',
name: '',
address: '',
children: [{
id: 6,
date: '电梯、爬梯1',
name: '100',
address: '是'
}, {
id: 7,
date: '电梯、爬梯2',
name: '100',
address: '是'
}]
}],
number: 100,
numberParent: 10000
}
},
mounted () {
this.tableData = this.addChildren(this.tableData)
console.log(this.tableData)
this.indexData(this.tableData)
},
methods: {
//子序列增加
indexData (val) {
val.forEach((item, index) => {
item.index = index + 1 + '';
if (item.children?.length > 0) {
this._indexData(item, item.index);
}
})
// this._indexData(item, oldIndex)
return val;
},
_indexData (item, oldIndex) {
if (item.children?.length < 0) return;
if (item.children?.length > 0) {
item.children.forEach((Item, i) => {
Item.index = oldIndex + '.' + (i + 1);
this._indexData(Item, Item.index);
});
}
},
addBig (row, index) {
this.number++
row.children.push({
id: this.number,
date: 'xxx',
name: '100',
address: '是',
children: []
})
this.indexData(this.tableData)
},
remove (row, index) {
this.deleteTable(row, index, this.tableData)
this.indexData(this.tableData)
},
rowClassName ({ row, columnIndex }) {
if (row.children && row.children.length) {
return "rowName"
}
},
deleteTable (row, index, arr) {
for (let i = 0; i < arr.length; i++) {
const element = arr[i]
if (element.id == row.id) {
arr.splice(i, 1)
} else {
if (element.children.length > 0) {
this.deleteTable(row, index, element.children)
} else {
}
}
}
},
addChildren (treeData) {
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i];
if (node.children?.length > 0) {
this.addChildren(node.children);
} else {
this.$set(node, 'children', [])
}
}
return treeData;
},
addBigParent () {
this.tableData.push({
id: this.numberParent++,
date: 'xxx',
name: '',
address: '',
children: []
})
this.indexData(this.tableData)
}
},
}
</script>
<style>
.el-icon-arrow-right:before {
content: none;
}
.el-table__expand-icon {
width: 0px !important;
margin-right: 0px !important;
}
.el-table__indent {
/* padding-left: 0px !important; */
}
.el-table__placeholder {
width: 0px !important;
}
.rowName {
background: #d4d4d4 !important;
font-size: 19px;
font-weight: 650;
color: #000;
}
.el-table__body tr.hover-row > td.el-table__cell {
background: none;
}
/* .el-table__expand-icon {
display: none !important;
} */
/* .el-table__expand-column {
display: none;
}
.el-table__row--level-1 td:first-child {
padding-left: 40px;
}
.el-table__row--level-2 td:first-child {
padding-left: 80px;
} */
/* 根据层级嵌套,设置不同的padding-left值 */
</style>
<template>
<div>
<el-button type="primary" @click="addBigParent">增加子集</el-button>
<el-table
class="table"
:data="table"
:key="key"
style="width: 100%; margin-bottom: 20px"
row-key="id"
border
default-expand-all
line
all-show-tooltip-when-overflow
highlight-current-row
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:row-class-name="rowClassName"
>
<el-table-column prop="index" label="序号" width="150"></el-table-column>
<el-table-column prop="date" label="检查内容" sortable width="180">
</el-table-column>
<el-table-column prop="name" label="标准值" sortable width="180">
</el-table-column>
<el-table-column prop="address" label="是否拍照"> </el-table-column>
<el-table-column prop="operate" label="操作" fixed="right">
<template slot-scope="scope">
<a
href="javascript:void(0);"
style="color: #147bd1"
@click="addBig(scope.row, scope.$index)"
>增加子集</a
>
<span style="color: #bbbec1"> | </span>
<a
href="javascript:void(0);"
class="delete"
@click="remove(scope.row, scope.$index)"
>删除</a
>
</template>
</el-table-column>
<div slot="empty">
<emptyContent></emptyContent>
</div>
</el-table>
</div>
</template>
<script>
import Sortable from 'sortablejs'
// 支持拖动的包含父级的拖动插件引入
export default {
data () {
return {
table: [{
id: 1,
date: '工具检查',
name: '',
address: '',
children: [{
id: 2,
date: '工具检查',
name: '',
address: '',
children: [{
id: 3,
date: '工具检查1',
name: '100',
address: '是'
}]
}, {
id: 4,
date: '工具检查2',
name: '100',
address: '是'
}]
}, {
id: 5,
date: '电梯、爬梯',
name: '',
address: '',
children: [{
id: 6,
date: '电梯、爬梯1',
name: '100',
address: '是'
}, {
id: 7,
date: '电梯、爬梯2',
name: '100',
address: '是'
}]
}
],
number: 100,
numberParent: 10000,
activeRows: [], // 转换为列表的数据扁平化
numberNew: null,
key: null,
tbody: null
}
},
mounted () {
this.table = this.addChildren(this.table)
this.indexData(this.table)
this.treeParent(this.table)
this.rowDrop()
console.log(this.table)
},
watch: {
table () {
this.rowDrop()
}
},
methods: {
//子序列增加
indexData (val) {
val.forEach((item, index) => {
item.index = index + 1 + '';
if (item.children?.length > 0) {
this._indexData(item, item.index);
}
})
// this._indexData(item, oldIndex)
return val;
},
_indexData (item, oldIndex) {
if (item.children?.length < 0) return;
if (item.children?.length > 0) {
item.children.forEach((Item, i) => {
Item.index = oldIndex + '.' + (i + 1);
this._indexData(Item, Item.index);
});
}
},
addBig (row, index) {
this.number++
row.children.push({
id: this.number,
date: 'xxx',
name: '100',
address: '是',
children: []
})
this.indexData(this.table)
this.treeParent(this.table)
},
remove (row, index) {
this.deleteTable(row, index, this.table)
this.indexData(this.table)
},
rowClassName ({ row, columnIndex }) {
if (row.children && row.children.length) {
return "rowName"
}
},
deleteTable (row, index, arr) {
for (let i = 0; i < arr.length; i++) {
const element = arr[i]
if (element.id == row.id) {
arr.splice(i, 1)
} else {
if (element.children.length > 0) {
this.deleteTable(row, index, element.children)
}
}
}
},
addChildren (treeData) {
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i];
if (node.children && node.children.length > 0) {
this.addChildren(node.children);
} else {
this.$set(node, 'children', [])
}
}
return treeData;
},
addBigParent () {
this.table.push({
id: this.numberParent++,
date: 'xxx',
name: '',
address: '',
children: []
})
this.indexData(this.table)
this.treeParent(this.table)
},
rowDrop () {
this.key = Symbol(new Date().toString())
this.$nextTick(() => {
this.tbody = document.querySelector('.table .el-table__body-wrapper tbody')
Sortable.create(this.tbody, {
animation: 200, // 定义排序动画的时间
forceFallback: true, // boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等;
onMove: ({ dragged, related }) => {
const oldRow = this.activeRows[dragged.rowIndex] // 移动的那个元素
const newRow = this.activeRows[related.rowIndex] // 新的元素
if (oldRow.parentId !== newRow.parentId) { // 移动的元素与新元素父级id不相同
return false // 不允许跨级拖动
}
},
onStart: () => { // 开始拖拽前把树形结构数据扁平化
this.activeRows = this.treeToTile(this.table) // 把树形的结构转为列表再进行拖拽
},
onEnd: e => {
const oldRow = this.activeRows[e.oldIndex] // 移动的那个元素
const newRow = this.activeRows[e.newIndex] // 新的元素
if (e.oldIndex === e.newIndex || oldRow.parentId !== newRow.parentId) return
const index = this.activeRows.indexOf(oldRow)
if (index < 0) return
const changeIndex = e.newIndex - e.oldIndex
this.activeRows.splice(index, 1)
this.activeRows.splice(index + changeIndex, 0, oldRow)
this.table = this.listToTree(this.activeRows)
this.activeRows = this.treeToTile(this.table)
this.indexData(this.table)
}
})
})
},
/**
* 将树数据转化为平铺数据
* @param <Array> treeData当前要转的id
* @param <String> childKey 子级字段
* @return <Array> 返回数据
*/
treeToTile (treeData, childKey = 'children') {
const arr = []
const expanded = data => {
if (data && data.length > 0) {
data.filter(d => d).forEach(e => {
arr.push(e)
expanded(e[childKey] || [])
})
}
}
expanded(treeData)
return arr
},
// 子级携带父级id
treeParent (treeData, childKey = 'children') {
const expandParent = (data, parentId) => {
if (data && data.length > 0) {
data.filter(d => d).forEach(e => {
if (parentId) {
this.$set(e, 'parentId', parentId)
}
expandParent(e[childKey] || [], e.id || '')
})
}
}
expandParent(treeData)
return treeData
},
listToTree (list) {
const map = {};
let node;
let roots = [];
for (let i = 0; i < list.length; i++) {
map[list[i].id] = i;
list[i].children = [];
}
for (let i = 0; i < list.length; i++) {
node = list[i];
if (node?.parentId) {
list[map[node.parentId]].children.push(node);
} else {
roots.push(node);
}
}
return roots;
}
}
}
</script>
<style>
.el-icon-arrow-right:before {
content: none;
}
.el-table__expand-icon {
width: 0px !important;
margin-right: 0px !important;
}
.el-table__indent {
/* padding-left: 0px !important; */
}
.el-table__placeholder {
width: 0px !important;
}
.rowName {
background: #d4d4d4 !important;
font-size: 19px;
font-weight: 650;
color: #000;
}
.el-table__body tr.hover-row > td.el-table__cell {
background: none;
}
/* .el-table__expand-icon {
display: none !important;
} */
/* .el-table__expand-column {
display: none;
}
.el-table__row--level-1 td:first-child {
padding-left: 40px;
}
.el-table__row--level-2 td:first-child {
padding-left: 80px;
} */
/* 根据层级嵌套,设置不同的padding-left值 */
</style>
<template>
<div class="a_tree_box">
<div>
<el-table
ref="cimsDictTable"
default-expand-all
:data="tableData"
style="width: 100%"
row-key="id"
border
stripe
size="mini"
class="data-table"
tooltip-effect="dark"
header-row-class-name="data-table-header"
lazy
:show-overflow-tooltip="true"
:load="load"
:tree-props="{ children: 'childNode' }"
@selection-change="handleSelectionChange"
@select="select22"
@select-all="selectAll"
>
<el-table-column label="条件" min-width="400px">
<template slot-scope="scope">
<!-- 这部分是设置虚线逻辑 -->
<template v-for="(item, l) in scope.row.level">
<!-- 根据delItemFlag判断 是true或者'true'则对应的竖虚线是多余的 需要删除 -->
<span
v-if="scope.row.delItemFlag[l] == 'false'"
:key="l + 1"
class="l_bor1_box"
:style="{ left: `${(l + 1) * 16 - 6}` + 'px' }"
></span>
<!-- 这个是设置横的虚线 -->
<span
v-if="l == scope.row.level - 1"
:key="(l + 1) * 10000"
class="l_bor2_box"
:style="{ left: `${(l + 1) * 16 - 6}` + 'px' }"
></span>
</template>
<!-- 这个是设置每个层级最后的那个节点 多加一个竖线 覆盖多余的行高虚线 -->
<span
v-if="scope.row.moreOneDash"
class="more_dash"
:style="{ left: `${scope.row.level * 16 - 6}` + 'px' }"
></span>
<span class="showName">{{ scope.row.conditionName }}</span>
<i
v-if="
scope.row.farOrSon == 'first' || scope.row.farOrSon == 'middle'
"
style="
font-size: 18px;
margin-left: 5px;
color: #00ff00;
cursor: pointer;
"
class="el-icon-folder-add"
@click="addOneRow(scope.row, scope.$index, 'middle')"
></i>
<i
v-if="
scope.row.farOrSon == 'first' || scope.row.farOrSon == 'middle'
"
style="
font-size: 18px;
margin-left: 5px;
color: #00ff00;
cursor: pointer;
"
class="el-icon-document-add"
@click="addOneRow(scope.row, scope.$index, 'last')"
></i>
<i
v-if="
scope.row.farOrSon == 'middle' || scope.row.farOrSon == 'last'
"
style="
font-size: 18px;
margin-left: 5px;
color: #f1ff;
cursor: pointer;
"
class="el-icon-edit"
@click="editRow(scope.row, scope.$index)"
></i>
<i
v-if="
scope.row.farOrSon == 'middle' || scope.row.farOrSon == 'last'
"
style="
font-size: 18px;
margin-left: 5px;
color: #1890ff;
cursor: pointer;
"
type="primary"
class="el-icon-close"
@click="delRow(scope.row, scope.$index)"
></i>
</template>
</el-table-column>
<el-table-column label="交强险(%)">
<el-table-column label="上游" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str1"
placeholder
@input="
scope.row.strObj.str1 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str1) ||
scope.row.strObj.str1 == ''
? scope.row.strObj.str1
: (scope.row.strObj.str1 = '')
"
></el-input>
</template>
</el-table-column>
<el-table-column label="基数" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str2"
placeholder
@input="
scope.row.strObj.str2 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str2) ||
scope.row.strObj.str2 == ''
? scope.row.strObj.str2
: (scope.row.strObj.str2 = '')
"
></el-input>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="车船险(%)">
<el-table-column label="上游" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str3"
placeholder
@input="
scope.row.strObj.str3 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str3) ||
scope.row.strObj.str3 == ''
? scope.row.strObj.str3
: (scope.row.strObj.str3 = '')
"
></el-input>
</template>
</el-table-column>
<el-table-column label="基数" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str4"
placeholder
@input="
scope.row.strObj.str4 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str4) ||
scope.row.strObj.str4 == ''
? scope.row.strObj.str4
: (scope.row.strObj.str4 = '')
"
></el-input>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="商业险(%)">
<el-table-column label="上游" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str5"
placeholder
@input="
scope.row.strObj.str5 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str5) ||
scope.row.strObj.str5 == ''
? scope.row.strObj.str5
: (scope.row.strObj.str5 = '')
"
></el-input>
</template>
</el-table-column>
<el-table-column label="基数" width="70px">
<template slot-scope="scope">
<el-input
v-if="scope.row.strObj"
v-model="scope.row.strObj.str6"
placeholder
@input="
scope.row.strObj.str6 =
/^d+.?d{0,2}$/.test(scope.row.strObj.str6) ||
scope.row.strObj.str6 == ''
? scope.row.strObj.str6
: (scope.row.strObj.str6 = '')
"
></el-input>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="操作" width="200px">
<template slot-scope="scope">
<span
v-if="
scope.row.farOrSon == 'first' || scope.row.farOrSon == 'middle'
"
style="color: #00ff00; cursor: pointer"
@click="addOneRow(scope.row, scope.$index, 'middle')"
>新增夹</span
>
<span
v-if="
scope.row.farOrSon == 'first' || scope.row.farOrSon == 'middle'
"
style="color: #00ff00; cursor: pointer"
@click="addOneRow(scope.row, scope.$index, 'last')"
>新增页</span
>
<span
v-if="
scope.row.farOrSon == 'middle' || scope.row.farOrSon == 'last'
"
style="color: #f1ff; cursor: pointer"
@click="editRow(scope.row, scope.$index)"
>编辑</span
>
<span
v-if="
scope.row.farOrSon == 'middle' || scope.row.farOrSon == 'last'
"
style="color: #2593fc; cursor: pointer"
@click="delRow(scope.row, scope.$index)"
>删除</span
>
</template>
</el-table-column>
</el-table>
<!-- 编辑回显的弹框 其实新增也可以用这个弹框但是没写 -->
<el-dialog
title="提示"
class="dia_box"
:visible.sync="dialogFlag"
width="500px"
>
<el-form :model="formData">
<el-form-item label="条件名称:" label-width="128px">
<el-input
v-model="formData.conditionName"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="交强险(%)上游:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str1"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="交强险(%)基数:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str2"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="车船险(%)上游:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str3"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="车船险(%)基数:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str4"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="商业险(%)上游:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str5"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item
v-if="formData.strObj"
label="商业险(%)基数:"
label-width="128px"
>
<el-input
v-model="formData.strObj.str6"
autocomplete="off"
></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogFlag = false">取 消</el-button>
<el-button type="primary" @click="changeRow">确 定</el-button>
</span>
</el-dialog>
<el-radio v-model="addOrEdit" :label="false">无数据列表</el-radio>
<el-radio v-model="addOrEdit" :label="true">有数据列表</el-radio>
<el-button @click="lookData">点击打印树表数据</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'TreeTable',
data () {
return {
addOrEdit: true, // false无数据列表 true是有数据列表
ref: 'cimsDictTable',
tableData: [], // 这个是真正的展示树状列表
selectAddLast: null, // 点击树表的添加 middle是添加中间 last 是添加最后末梢
cimsDictTable: [],
sourceData: [
{
id: 3, // 注意数据必须要有id 否则树状数据渲染会出问题 那么我们可以再前端新增时候以时间戳为id 真正保存到数据库后会有真实id
conditionName: '顶级条件',
strObj: null,
parentId: null,
childNode: [] // childNode有值 就会形成对应的嵌套下级
}
],
dialogFlag: false,
formData: {
id: null,
conditionName: '',
strObj: {
str1: '',
str2: '',
str3: '',
str4: '',
str5: '',
str6: ''
}
}
}
},
watch: {
addOrEdit (val) {
if (!this.addOrEdit) {
// 打开一个全新的列表
this.getNewData()
} else {
// 根据id找到某个数据列表 回显 假设id是123
this.getIdDate(123)
}
}
},
mounted () {
if (!this.addOrEdit) {
// 打开一个全新的列表
this.getNewData()
} else {
// 根据id找到某个数据列表 回显 假设id是123
this.getIdDate(123)
}
},
beforeMount () {
},
methods: {
getNewData () {
this.$set(this.sourceData[0], 'childNode', [])
this.initData()
},
// 获取页面数据回显
getIdDate (id) {
// 总数据回显 --- 假设给的数据 这条数据是默认数据的childNode
let dataArr = [
{
id: 31,
conditionName: '条件--【页】--页不可添加下级 是末梢last',
strObj: {
str1: '11',
str2: '22',
str3: '1',
str4: 2,
str5: '2',
str6: '2'
},
parentId: 3,
childNode: []
},
{
id: 32,
conditionName: '条件--【夹】--夹可以添加下级 是中间middle',
strObj: null,
parentId: 3,
childNode: [
{
id: 311,
conditionName: '机密的任务',
strObj: null,
parentId: 32,
childNode: [
{
id: 3221,
conditionName: '这个条件名字比较长 会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行',
strObj: {
str1: '11',
str2: '121',
str3: '1',
str4: 2,
str5: '2',
str6: '2'
},
parentId: 311,
childNode: []
},
{
id: 3222,
conditionName: '9527',
strObj: {
str1: '11',
str2: '1',
str3: '1',
str4: 2,
str5: '2',
str6: '2'
},
parentId: 311,
childNode: []
},
{
id: 3223,
conditionName: '夹文件',
strObj: null,
parentId: 311,
childNode: []
}
]
},
{
id: 321,
conditionName: '附加条件-日后再说',
strObj: {
str1: '11',
str2: '33',
str3: '1',
str4: 2,
str5: '2',
str6: '2'
},
parentId: 3,
childNode: []
}
]
},
{
id: 33,
conditionName: '条件夹',
strObj: null,
parentId: 3,
childNode: []
}
]
// // 设置id---没有id树渲染会报错--
// let num = 121210
// function setId (arr, pId) {
// for (let j = 0; j < arr.length; j++) {
// const element = arr[j]
// if (element.childNode.length == 0) {
// element['id'] = num
// element['parentId'] = pId
// num++
// } else {
// element['id'] = num
// element['parentId'] = pId
// num++
// setId(element.childNode, element['id'])
// }
// }
// }
// setId(dataArr, 983873292643)
// console.log(dataArr)
// 获取数据嵌套的层级
function setLevel (arr, levelNum) {
for (let j = 0; j < arr.length; j++) {
const element = arr[j]
if (element.childNode.length == 0) {
element['level'] = levelNum
} else {
element['level'] = levelNum
setLevel(element.childNode, levelNum + 1)
}
}
}
setLevel(dataArr, 1)
this.$set(this.sourceData[0], 'childNode', dataArr)
console.log(this.sourceData)
this.initData()
},
// 在树表每次数据变化时候 新增 删除 编辑 都需要设置出新的状态 判断是中间层 而没有子集
checkEveryItem () {
// 这一步是找到空的中间层 需要添加页
let noChildAndNoRate = []
function checkIsNeedChild (arr, ruleName) {
for (let j = 0; j < arr.length; j++) {
const element = arr[j]
if (element.childNode.length == 0) {
if (element.strObj == null || element.strObj == 'null') {
element['isNeedLast'] = true
noChildAndNoRate.push({ cantName: ruleName.trim() + '/' + element.conditionName.trim() })
} else {
element['isNeedLast'] = false
}
} else {
element['isNeedLast'] = false
checkIsNeedChild(element.childNode, ruleName.trim() + '/' + element.conditionName.trim())
}
}
}
checkIsNeedChild(this.tableData, '')
console.log('中间层的子集为空也就是没末梢', noChildAndNoRate)
// 这个是找到每层级最后一个 判断是中间层 且 还有childNode 那么他的childNode就需要删除多余虚线(子集childNode多余的虚线就是父级的的那个嵌套层级 那条虚线)
// 第一步先找到 父级(满足最后一层是中间层 且有子集childNode)
function set_setLast (arr) {
for (let j = 0; j < arr.length; j++) {
const element = arr[j]
if (element.childNode.length == 0) {
if (j == (arr.length - 1)) {
// element['isLastZhongjianAndHasChl'] = true
if ((element.strObj == null || element.strObj == 'null') && element.childNode.length > 0) {
element['isLastZhongjianAndHasChl'] = true
} else {
element['isLastZhongjianAndHasChl'] = false
}
} else {
element['isLastZhongjianAndHasChl'] = false
}
} else {
if (j == (arr.length - 1)) {
// element['isLastZhongjianAndHasChl'] = true
if ((element.strObj == null || element.strObj == 'null') && element.childNode.length > 0) {
element['isLastZhongjianAndHasChl'] = true
} else {
element['isLastZhongjianAndHasChl'] = false
}
} else {
element['isLastZhongjianAndHasChl'] = false
}
set_setLast(element.childNode)
}
}
}
// console.log(this.tableData[0].childNode)
set_setLast(this.tableData[0].childNode)
this.tableData[0]['isLastZhongjianAndHasChl'] = true
// 第二步 根据isLastZhongjianAndHasChl和所需要删除的层次level 递归遍历 将需要删除虚线的标志为true fasle是不删 将几条虚线删不删的值放在一个数组内
function delArrItem (arr, flagDel, num, farArr) {
for (let j = 0; j < arr.length; j++) {
const element = arr[j]
let delItemFlag = JSON.parse(JSON.stringify(farArr)) // 必须深拷贝 将父级的数组继承到子集使用 深拷贝 才不会改变父级数组值
for (let h = 0; h < element.level; h++) {
if (flagDel == 'true' || flagDel == true) {
if ((h + 1) == num) {
delItemFlag[h] = 'true'
} else {
if (delItemFlag[h] == 'true' || delItemFlag[h] == true) { // 针对需要删除的 就不要再赋值
} else {
delItemFlag[h] = 'false'
}
}
} else {
if (delItemFlag[h] == 'true' || delItemFlag[h] == true) {
} else {
delItemFlag[h] = 'false'
}
}
}
element['delItemFlag'] = delItemFlag
if (element.childNode.length == 0) {
} else {
delArrItem(element.childNode, element.isLastZhongjianAndHasChl, element.level, element['delItemFlag'])
}
}
}
delArrItem(this.tableData[0].childNode, false, 0, [])
// this.tableData[0]['isLastZhongjianAndHasChl'] = true
// 这个是找到每层级最后一个 然后标志出来true 最后画虚线时候需要 单独多画一个线用来遮挡多余的当前层虚线(因为行高自适应 当某层的末梢行高超过50px时候 之前设置的top: -24px就不够了 会多出来一部分虚线 故需要遮挡掉)
function set_lastMoreDash (arr) {
for (let j = 0; j < arr.length; j++) {
const element = arr[j]
if (element.childNode.length == 0) {
if (j == (arr.length - 1)) {
element['moreOneDash'] = true
} else {
element['moreOneDash'] = false
}
} else {
if (j == (arr.length - 1)) {
element['moreOneDash'] = true
} else {
element['moreOneDash'] = false
}
set_lastMoreDash(element.childNode)
}
}
}
set_lastMoreDash(this.tableData[0].childNode)
console.log('处理虚线', this.tableData)
},
lookData () {
console.log('tableData--', this.tableData)
},
Menuclose () {
this.dialogVisibleMenu = false
},
setRowData (row, parentId, farOrSon, val) {
let strObj = null
if (farOrSon == 'last') {
strObj = {
str1: '',
str2: '',
str3: '',
str4: '',
str5: '',
str6: ''
}
} else {
strObj = null
}
return {
id: new Date().valueOf(),
conditionName: val.newName,
parentId: parentId || null,
strObj: strObj,
edit: true,
add: true,
childNode: [],
level: (row.level >= 0) ? (row.level + 1) : 1,
farOrSon: farOrSon
}
},
// 手动勾选数据行
select22 (selection, row) {
// 判断当前行是否选中
// 不需要判断 id, 因为引用地址相同
const selected = selection.some((item) => item === row)
// 处理所有子级
this.selectChildren(row, selected)
},
selectAll (selection) {
/*
* 这里引用别人的代码:
* selectAll 只有两种状态: 全选和全不选
* 所以我们只需要判断一种状态即可
* 而且也不需要判断 id, 因为 selection 和 this.data 中对象引用地址是相同的
*/
// tableData 第一层只要有在 selection 里面就是全选
const isSelect = this.tableData.some((item) => selection.includes(item))
if (isSelect) {
selection.forEach((item) => {
this.selectChildren(item, isSelect)
})
} else {
this.tableData.forEach((item) => {
this.selectChildren(item, isSelect)
})
}
},
selectChildren (row, selected) {
if (row['childNode'] && Array.isArray(row['childNode'])) {
row['childNode'].forEach((item) => {
this.toggleSelection(item, selected)
this.selectChildren(item, selected)
})
}
},
selectionChange (selection) {
this.debounce(this.tableSelectChange, 100, selection)
},
toggleSelection (row, select) {
row &&
this.$nextTick(() => {
this.$refs[this.ref] &&
this.$refs[this.ref].toggleRowSelection(row, select)
})
},
// 防抖
debounce (fun, wait, params) {
clearTimeout(this.timeout)
this.timeout = setTimeout(fun, wait, params)
},
getSelectedList () {
// 获取选中数据源
let list = JSON.parse(JSON.stringify(this.cimsDictTable))
list.forEach((e) => (e.childNode = null))
return list
},
addRow (row, id, farOrSon, val) {
console.log(row, id)
// 去掉这个if和else是 为了达到可以不保存 就继续添加下级
// if (!row.add) {
// 新增行数据
let addrow = this.setRowData(row, row.id, farOrSon, val)
// 新增
if (row.childNode) {
row.childNode.push(addrow)
} else {
// 添加数据
this.$set(row, 'childNode', [addrow])
}
// 展开行
this.$nextTick(() => {
// 更新后打开节点
this.$refs.cimsDictTable.toggleRowExpansion(row, true)
// 刷新树
this.refTable()
})
// } else {
// this.$message({
// message: '请保存后再继续添加子节点!',
// type: 'warning'
// })
// }
// 每次添加编辑删除树表需要 重新计算出新属性状态
this.checkEveryItem()
},
addOneRow (row, index, farOrSon) {
this.selectAddLast = farOrSon
let item = {}
let val = { newName: `新的条件${Math.floor(Math.random() * (1 - 1000) + 1000)}` }// 假设这个就是新增是一行的值
console.log(1123, val)
function findRow (arrA, Id, val) {
for (let h = 0; h < arrA.length; h++) {
const element = arrA[h]
if (element.childNode.length == 0) {
if (element.id == Id) {
item = element
}
} else {
if (element.id == Id) {
item = element
}
findRow(element.childNode, Id, val)
}
}
}
findRow(this.tableData, row.id, val)
this.addRow(item, row.id, this.selectAddLast, val)
},
updateTableTree (parentId, nodes) {
// 更新需要先更新上级节点
this.$set(
this.$refs.cimsDictTable.store.states.lazyTreeNodeMap,
parentId,
nodes
)
},
refTable () {
let _this = this
function dg (data) {
for (let i in data) {
if (data[i].childNode) {
_this.updateTableTree(data[i].id, data[i].childNode)
dg(data[i].childNode)
}
}
}
dg(this.tableData)
},
// 删除当前条及对应下级数据
deleteTable (row, index, arr) {
for (let i = 0; i < arr.length; i++) {
const element = arr[i]
if (element.id == row.id) {
arr.splice(i, 1)
} else {
if (element.childNode.length > 0) {
this.deleteTable(row, index, element.childNode)
} else {
}
}
}
},
delRow (row, index) {
console.log(row, index)
this.$confirm('确认删除该条件及下级条件?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.deleteTable(row, index, this.tableData)
// 每次添加编辑删除树表需要 重新计算出新属性状态
this.checkEveryItem()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
// 删除行
let delArr = []
function dg (data) {
for (let i in data) {
// 过滤当前新增的数据
if (!data[i].add) {
delArr.push(data[i].id)
}
if (data[i].childNode) {
dg(data[i].childNode)
}
}
}
dg([row])
// 删除
},
editRow (row, index) {
// 编辑
this.$set(row, 'edit', true)
// 使用深拷贝 否则会影响改弹框 就直接影响列表数据了 我们要的是改了弹框点击确认才改列表数据 故需要深拷贝
this.formData = JSON.parse(JSON.stringify(row))
this.dialogFlag = true
},
// 点击了弹框的确定
changeRow () {
let val = this.formData
function findId (arrA, Id, val) {
for (let h = 0; h < arrA.length; h++) {
const element = arrA[h]
if (element.childNode.length == 0) {
if (element.id == Id) {
element['conditionName'] = val.conditionName
element['strObj'] = val.strObj
console.log(12121, element, val)
}
} else {
if (element.id == Id) {
element['conditionName'] = val.conditionName
element['strObj'] = val.strObj
console.log(12121, element, val)
}
findId(element.childNode, Id, val)
}
}
}
findId(this.tableData, val.id, val)
this.dialogFlag = false
// 每次添加编辑删除树表需要 重新计算出新属性状态
this.checkEveryItem()
},
proTableData (data) {
let _this = this
// 处理数据
function dg (data) {
for (let i in data) {
_this.$set(data[i], 'edit', false)
if (data[i].childNode) {
// 重要:树状节点数据刷新
_this.updateTableTree(data[i].id, data[i].childNode)
dg(data[i].childNode)
}
}
}
dg(data)
// 给数据判断添加父子节点标识
function setFarSon (data) {
for (let index = 0; index < data.length; index++) {
const element = data[index]
// console.log(element.parentId, element.parentId == undefined)
if (element.parentId == undefined || element.parentId == null) {
element['farOrSon'] = 'first'
setFarSon(element.childNode)
} else {
if (element.strObj == null || element.strObj == 'null') {
element['farOrSon'] = 'middle'
setFarSon(element.childNode)
} else {
element['farOrSon'] = 'last'
}
}
}
}
setFarSon(data)
},
initData () {
// 数据加载 模仿数据请求
let res = JSON.parse(JSON.stringify(this.sourceData))
// 数据处理 添加编辑标识
this.proTableData(res)
this.tableData = res
// 每次添加编辑删除树表需要 重新计算出新属性状态
this.checkEveryItem()
},
load (tree, treeNode, resolve) {
// 节点加载
setTimeout(() => {
resolve(tree.childNode)
}, 1000)
},
handleSelectionChange (val) {
// 全选
this.cimsDictTable = val
}
}
}
</script>
<style lang="scss" scoped>
// 树状表格样式
.a_tree_box {
width: calc(100vw - 300px);
height: 100%;
margin-bottom: 20px;
padding: 40px;
.cd-tool {
display: flex;
flex-direction: row;
}
.data-table {
.cell {
display: flex;
align-items: center;
}
// 固定表格高度
td {
height: 50px;
padding: 0;
}
tbody {
tr {
overflow: hidden;
td {
// width: 40px !important;
// background-color: #1fff!important;
// background-color: rgba(255, 255, 255, 0); //必须设置为透明色 否则 warning-row 显示不出来
.cell {
padding: 0 !important;
// background-color: #1fff;
height: 100%;
position: relative;
overflow: visible !important;
.l_bor1_box {
top: -24px;
display: inline-block;
width: 1px;
height: 100%;
border-left: 1px dashed #ccc;
position: absolute;
}
.l_bor2_box {
display: inline-block;
width: 30px;
height: 1px;
border-top: 1px dashed #ccc;
position: absolute;
}
.more_dash {
display: inline-block;
width: 1px;
height: 50%;
border-top: 1px dashed #ccc;
position: absolute;
top: calc(50% - 1px);
// background-color: rgba(248, 250, 252, 1);
background-color: rgb(255, 253, 253);
}
.el-table__expand-icon {
//这个是将所有的条件前面的图标 固定掉
display: inline-block;
width: 20px !important;
min-width: 20px !important;
position: relative;
z-index: 999;
// background-color: #1fff;
}
.el-table__placeholder {
//这个是将所有的条件前面的空白 固定成20px 这样才会有间隔层级视觉效果 如果不做固定 会导致 条件文字多的时候 有的是20xp 有的不是 就导致看起来没层级一样
display: inline-block;
width: 25px !important;
max-width: 25px !important;
min-width: 25px !important;
}
.l_bor3_box {
display: inline-block;
width: 1px;
height: 15px;
border-left: 1px dashed #ccc;
top: 15px;
left: -13px;
position: relative;
}
}
}
td:nth-child(n + 2) {
.cell {
span {
// background-color: #1fff;
display: inline-block;
width: 100%;
text-align: center;
}
}
}
}
}
}
.showName {
display: inline-block;
// max-width: 100px;
// white-space: nowrap;
white-space: wrap;
overflow: hidden;
text-overflow: ellipsis;
}
.one_two {
width: 20px;
height: 20px;
margin-right: 3px;
}
.isML10 {
margin-left: 10px; //判断有无数据 没数据就需要左偏移对齐
}
.abcd {
width: 20px;
height: 20px;
cursor: pointer;
margin-left: 3px;
}
.tip_icon {
width: 20px;
height: 20px;
cursor: pointer;
position: relative;
top: -1px;
left: 30px;
}
.tip_box {
display: inline-block;
width: fit-content !important;
min-width: 105px;
color: red;
font-weight: 700;
position: relative;
top: 1px;
margin-left: 33px;
font-size: 17px;
}
.el-input__inner {
margin-left: 3px !important;
padding: 0 !important;
width: 44px !important;
height: 25px !important;
text-align: center !important;
}
.dia_box {
.el-input {
text-align: left;
.el-input__inner {
width: 300px !important;
height: 35px !important;
text-align: left !important;
}
}
}
}
</style>
实现把树里的某个url对象以list的形式输出出来
let arr = [{
fileList:[],
children: [
{
fileList:[{url: 'https://1.png'}, {url: 'https://2.png'}],
children: []
},
{
fileList:[{url: 'https://3.png'}],
children: []
}
]
},{
fileList:[{url: 'https://4.png'}],
children: [
{
fileList:[],
children: []
},
{
fileList:[{url: 'https://5.png'}],
children: []
}
]
}]
我想要这个 ['https://1.png', 'https://2.png', 'https://3.png', 'https://4.png', 'https://5.png']
this.urlList = this.extractImageUrls(this.tableData)
extractImageUrls (arr) {
let urls = [];
arr.forEach(item => {
if (item.fileList && item.fileList.length > 0) {
item.fileList.forEach(file => {
urls.push(file.url);
});
}
if (item.children && item.children.length > 0) {
urls = urls.concat(this.extractImageUrls(item.children));
}
});
return urls;
},