前端相关知识

🌷pnpm 清缓存

pnpm 清缓存
pnpm store prune

🌷 伪类写小竖线

 .sbi-col {
        width: 33%;
        text-align: center;
        position: relative;

        & + .sbi-col:after {
          position: absolute;
          content: "";
          left: 0;
          top: 16px;
          width: 1px;
          height: 12px;
          background-color: #004e9b;
        }

🌷 vscode注释

	单行注释 ctrl + /
	多行注释 shift + alt + a

🌷 计算属性 传参与不传参数

	//计算属性只能设置一次 不能再次更改值
	//1
	computed: {
		hostId: function() {
			return this.$route.query.hostId
		},
		valueType(vt) {
			return function(vt) {
				return '111'
			}
		}
	},
	//2 
	{{ valueType(scope.row.valueType) }}

🌷 路由缓存

	//1路由页面 name 要与指向的页面一致
	//2
	meta noCache: false
	{
	// path: 'testmodel',
	path: 'testmodel/:id/:type/:ip/:num',
	component: () => import('@/views/test-model/tmnew'),
	name: 'TestModel',
	meta: { title: '测试模型', icon: 'chart', noCache: false }
	},

🌷 同一路由参数不同

	//1路由路径用参数形式占位
	path: 'testmodel/:id/:type/:ip/:num',
	//2传递参数 用params传递 
	this.$router.push({
	name: 'TestModel',
	params: { ip, type, num, id: row.id }
	})
	//3拿取参数 用params
	if (this.$route.params.id !== ':id') {
	// if (this.$route.params.id) {
	const query = { hostId: this.$route.params.id }

🌷某一页面不显示左侧菜单和顶部导航栏

	//把路由放在第一层 这样就脱离框架
	{
	path: '/testmodel',
	component: () => import('@/views/test-model/tm'),
	name: 'TestModel',
	meta: { title: '测试模型', icon: 'chart', noCache: true },
	hidden: true
	},

🌷 根据条件动态创建class

	//第一种
	:class="topstatus?'module-block-ab-open':'module-block-ab-close'"
	//第二种
	:class="{'s-m-tab-item-active' : menuIndex === 1}"

🌷动态style

  :style="{
                cursor: item.disable ? 'pointer' : 'default'
              }"

🌷 vue 大屏定时器刷新

	created() {
		this.getTime()
		const _this = this
		this.upData = setInterval(() => {
			_this.getTime()
		}, parseInt(30 * 1000))
	},
	beforeDestroy() {
		if (this.upData) {
			clearInterval(this.upData)
		}
	},

🌷 props传递参数

props: {
	type: {
		type: String,
		default: ''
		}
},

🌷 路由跳转

this.$router.push(
	{
		name: 'CollectedPapers',
		//parms:{}
		//query:{}
	}
)

🌷 密码验证

	//1 验证所有情况都要 callback() 否则不生效
	var validatePass = (rule, value, callback) => {
		if (value === '') {
			callback(new Error('请输入密码'))
		} else {
			if (this.registerForm.confirmPwd !== '') {
				this.$refs.registerForm.validateField('confirmPwd')
			}
			callback()
		}
	}
	var validatePass2 = (rule, value, callback) => {
		if (value === '') {
			callback(new Error('请再次输入密码'))
		} else if (value !== this.registerForm.password) {
			callback(new Error('两次输入密码不一致!'))
		} else {
			callback()
		}
	}
	//2 表单规则
	password: [
		{ required: true, message: '请输入密码', trigger: 'blur' },
		{
			min: 6,
			max: 16,
			message: '长度在 6 到 16 个字符',
			trigger: 'blur'
		},
		{ validator: validatePass, trigger: 'blur' }
	],
	confirmPwd: [
		{ required: true, message: '请确认密码', trigger: 'blur' },
		{ validator: validatePass2, trigger: 'blur', required: true }
	]

🌷 手机号验证

// 验证号的规则
var checkMobile = (rule, value, cb) => {
	const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
	if (regMobile.test(value)) {
		return cb()
	}
	cb(new Error('请输入合法的手机号'))
}

🌷store里面设置 session

const user = {
  state: {
    type:
      getStore({
        name: 'type',
      }) || 'sso',  
  },

mutations: {
    SET_TYPE: (state, data) => {
      state.type = data
      setStore({
        name: 'type',
        content: state.type,
        type: 'session',
      })
    },
    }

🌷 设置public全局变量 打包后可更改

在public里面建一个config.js
在这里插入图片描述
在index.html 里面引用 然后全局就可以使用 Glob.ydUrl在这里插入图片描述

🌷dispatch 等待请求返回后再执行下一步

//第一种 定义一个变量接一下 await
    const data = await store.dispatch(
            'user/getMenu',
            store.state.user.roleId,
          )
      处理下一步逻辑


//第二种

store.dispatch(
            'user/getMenu',
            store.state.user.roleId,
          ).then(()=>{
          //在这里处理下一步逻辑
          })

**

🌷 获取过去/未来N天的日期 年月日时分秒

**

npm install dayjs --save

var dayjs = require('dayjs')
//今天 
 dayjs().format('YYYY-MM-DD HH:mm:ss')

//获取过去/未来N天的日期

dayjs().subtract(-1, 'day').format('YYYY-MM-DD HH:mm:ss')
dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')

🌷 下载node历史版本

打开 https://nodejs.org/zh-cn/download/releases/ 找到自己要的旧版

https://nodejs.org/zh-cn/download/releases/

或者这个网址:https://nodejs.org/dist/

有的项目用不同的node版本 ,可以下载几个,在环境变量里面相互切换
在这里插入图片描述

在这里插入图片描述

🌷 post请求参数只传递参数值

export function getWeChatDetail(data) {
  return request({
    baseURL,
    url: '',
    method: 'post',
    // 数据不是键值对格式,只有参数值
    headers: { 'Content-Type': 'application/json' },
    data
  })
}

🌷 临时存储分支文件,用于切换其他分支

🚚 选中vscode侧边git目录
🚚 点击上方…,选择存储(stash),取名字。
🚚 若存在新创建的文件,选择…,选择存储未追踪(stash Include untraked ),取名字。
✨🎄🎅🏼 ꕀ 🧜🏻‍♀️ 🧛🏻‍♂️👻 ✨🎅🏼 🎄 ꕀ 🧜🏻‍♀️ 🧛🏻‍♂️👻
🚚 切换回来后,选择…,选择存储,选择应用最新存储。
🚚 切换回来后,选择…,选择存储,选择应用存储。

🌷 git 克隆代码时候,使用其他有权限用户的账户密码。

🚚 例如 账号
🧜🏻‍♀️账户:zyy 密码 :123
✨将账号密码拼接在ip前面
✨格式= 账号:密码@地址
👻http://zyy:123@10:10:10:10:8888/xxx.git

🌷初始化仓库

🚚进入文件目录

cd existing_folder 

🚚初始化

git init 

🚚设置远程地址

git remote add origin http://x.x.x.x:8888/xxxx.git

🚚添加缓存

git add .

🚚提交

git commit -m "Initial commit"

🚚推送

git push -u origin master

🌷npm 安装包时报错 npm install rollbackFailedOptional: verb npm-session 解决办法

🚚第一种

npm --registry https://registry.npm.taobao.org install -g + 包名

🚚第二种

npm install -g cnpm --registry=https://registry.npm.taobao.org 来安装一个cnpm,然后再用cnpm install -g 包名

🌷git 不验证提交代码

🚚 git pull
🚚 git add .
🚚 git commit -m '修改内容' --no-verify
🚚 git push

🌷 修改父组件的值

🚚第一种
子组件 派发事件 $emit,父组件监听 。
父组件 写事件去修改

🚚第二种
子组件

this.$emit('update:aaa', '在子组件中修改父组件的值')

父组件绑定

:value.sync="aaa"

🚚第三种 如果是传递进来的值为对象,可以给 对象里的属性直接赋值

this.formConf.fields = […formConfBackup.fields]

如果是公共组件想要修改父组件的值,尽量使用第三种,不然每次调用组件,都要在父组件多写一些代码

🌷安装依赖

建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题

npm install --registry=https://registry.npm.taobao.org

🌷表单验证 prop多层结构 验证

 <el-form-item
              label="cron表达式"
              prop="warnJson.cron"
              :rules="[
                {
                  required: true,
                  message: 'cron表达式不能为空',
                  trigger: 'blur',
                },
              ]"
            >
              <div class="infoLabel">
                <el-input
                  @click.native="cronOpen = true"
                  v-model="form.warnJson.cron"
                  placeholder="请输入cron表达式"
                  class="inputWidth"
                />
              </div>
            </el-form-item>

🌷 数组去重

  list = [...new Set(list)];

🌷 正则提取字符中 ${ccc} 里面变量值

   extractVariable(str) {
      const reg = /\$\{(.+?)\}/;
      const reg_g = /\$\{(.+?)\}/g;
      const result = str.match(reg_g);
      console.log("result=", result);

      let list = [];
      for (let i = 0; i < result.length; i++) {
        const item = result[i];
        list.push(item.match(reg)[1]);
      }
  // 数组去重

list = […new Set(list)];

return list;
},

🌷 列居中

	display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

🌷 gutter 列与列的间距

<el-row :gutter="10">
    <el-col :span="12">

🌷函数里面取不到this 改用箭头函数

🌷删除文件

 beforeRemove(file) {
      // return this.$confirm(`确定移除 ${file.name}?`);
       const p = new Promise((resolve, reject) => {
      this.$confirm("此操作将删除该文件, 是否继续?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
         type: "warning",
        })
         .then(() => {
          deleteFile(file.id).then((res) => {
            if (res.code === 0) {
            resolve(true);
            //删除文件列表的文件
              this.fileList = this.fileList.filter((item) => {
                 return item.id !== file.id;
             });
             } else {
             this.$message({
              type: "error",
                 message: res.msg,
            });
             reject(false);
            }
          });
       })
       .catch(() => {
         this.$message({
             type: "info",
              message: "已取消删除",
            });
           reject(false);
         });
    });
    return p;
    },

🌷 文本域高度固定 不缩放

<el-input
                :disabled="disabled"
                class="form-title-textarea"
                type="textarea"
                v-model="queryParams.intro"
                placeholder="请输入项目介绍"
                resize="none"
              ></el-input>

🌷 子组件调动父组件的方法

this.$parent.getList()

🌷 子组件设置父组件的值

this.$parent.clickShow = false

🌷 全局挂载 方法和组件

在这里插入图片描述

🌷 utils里面导出的方法

import {dataAdd1} from "@/utils/dateUtils";

// 在vue文件 <script>里面引用,
// 如果想在<tempet>里面引用,需要在 data里面定义一个变量接收的这个方法.
 data() {
    return {
     ddd: dataAdd1,
    };
  },

🌷 vue 数据不响应化,不只是表单

🚚 在表单定义字段

form:{
cy:'111'
}

🚚 未在表单定义字段 响应化

 this.$set(this.from,'cy',‘123)

🌷 树结构找到第一个满足指定节点的 node

//找到首次出现 执行节点----------------
    findFirstExecutiveNode(node) {
      if (node.feature === "EXECUTIVE_NODE") {
        return node;
      }
      if (node.children && node.children.length > 0) {
        for (const child of node.children) {
          const foundNode = this.findFirstExecutiveNode(child);
          if (foundNode) {
            return foundNode;
          }
        }
      }
      return null;
    },
    findFirstExecutiveNodeInList(data) {
      for (const item of data) {
        const foundNode = this.findFirstExecutiveNode(item);
        if (foundNode) {
          return foundNode;
        }
      }
      return null;
    },
//调用
this.checkDataTree = this.findFirstExecutiveNodeInList(
                this.dataTree
              );

    //----------------------------------

🌷头像加载显示失败图片

   <el-avatar :size="33" :src="imageApi + avatar" @error="errorHandler">
            <img src="@/assets/logo/avatar.jpg" />
          </el-avatar>

🌷下载各种类型的文件

 down(row) {
      tsmConsultNoticeDownload(row.id).then(res => {
        let suffix = row.url.substring(row.url.lastIndexOf("."))
        let blob
        if (suffix=='.xls'){
          blob = new Blob([res], {type: "application/vnd.ms-excel"});
        }else if (suffix=='.xlsx'){
          blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
        }else if (suffix=='.pdf'){
          blob = new Blob([res], {type: "application/pdf"});
        }else if (suffix=='.doc'){
          blob = new Blob([res], {type: "application/msword"});
        }else if (suffix=='.docx'){
          blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"});
        }else if (suffix=='.png'){
          blob = new Blob([res], {type: "pplication/pdf"});
        }else if (suffix=='.ppt'){
          blob = new Blob([res], {type: "application/vnd.ms-powerpoint"});
        }else if (suffix=='.png'){
          blob = new Blob([res], {type: "image/png"});
        }else if (suffix=='.pptx'){
          blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.presentationml.presentation"});
        }else if (suffix=='.jpeg'){
          blob = new Blob([res], {type: "image/jpeg"});
        }else if (suffix=='.zip'){
          blob = new Blob([res], {type: "application/zip"});
        }else if (suffix=='.7z'){
          blob = new Blob([res], {type: "application/x-7z-compressed"});
        }else if (suffix=='tar'){
          blob = new Blob([res], {type: "application/x-tar"});
        }else if (suffix=='.7z'){
          blob = new Blob([res], {type: "application/x-7z-compressed"});
        }
        let url = window.URL.createObjectURL(blob);
        const link = document.createElement("a"); // 创建a标签
        link.href = url;
        link.download = row.fileName; // 重命名文件
        link.click();
        URL.revokeObjectURL(url); // 释放内存
      })
    },

🌷el-upload中 http-request 方法传参数

  // :http-request="(file) => uploadFile(file, row)"
<el-upload
                        class="upload-demo"
                        action=""
                        multiple
                        :show-file-list="false"
                        :file-list="row.rectificationPics"
                        :on-change="beforeUpload"
                        :http-request="(file) => uploadFile(file, row)"
                        accept=".jpg,.jpeg,.png"
                      >
                        <div class="avatar-uploader-icon">
                          <img
                            src="@/assets/images/editTable/addImg.png"
                            alt="上传图片"
                          />
                          <p>上传图片</p>
                        </div>
                      </el-upload>
	  uploadFile(files, row) {
	      const { file } = files;
	      const formData = new FormData();
	      formData.append("file", file);
	      formData.append("title", file.name);
	      formData.append("allowedSize", 20); }
	```


## 🌷 ES6中利用map取出数组对象中的id

```javascript
var newArr=arr.map((v)=> v.id);

🌷 object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度

object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。
object-fit 一般用于 img 和 video 标签,一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。
您可以通过使用 object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。

img.a {
  width: 200px;
  height: 400px;
  object-fit: cover;
}

🌷 await 数据返回后再处理同步的数据 用变量接一下返回值

 let { data } = await tsmConsultNoticeExcelInit("213");

🌷 @click.stop 阻止事件向父级元素传递

 <div @click="fun">
    <div @click.stop>
      <!--子div-->
    </div>
  </div>

  <div @click="doSomething">
    <button @click.stop="doSomethingElse">不会触发父级元素的点击事件</button>
  </div>

🌷防抖

import { debounce } from "throttle-debounce"; 

//第一种
 handleNodeClick: debounce(500, function (data) {
      this.queryParams.participatingDeptIds = data.deptId;
      //刷新列表
      this.getUnitNameList();
      this.getList();
    }),
//第二种
created() {
    this.aa = debounce(1000, (data) => {
      console.log(11111);
      this.queryParams.participatingDeptIds = data.deptId;
      //刷新列表
      this.getUnitNameList();
      this.getList();
    });
  },
//方法调用
this.aa(data);

🌷若依按钮权限

<eos-button
          class="eos-button-spacing"
          type="primary"
          icon="el-icon-circle-plus-outline"
          @click="senior()"
          v-hasPermi="['psm:person:advanceexternaladdress']"
          >高级功能</eos-button
        >

🌷echarts图行点击事件 防止触发多次调用。

  this.chart.off("click"); // 重点代码 避免点击事件重复执行
      this.chart.on("click", (param) => {
        let val = "";
        if (this.id == "business-visits") {
          //业务
          val = param.data.code;
          this.$emit("pieSeclet1", val);
        } else {
          //服务器
          val = param.name;
          this.$emit("pieSeclet2", val);
        }
      });

🌷 font 标签

规定文本的字体、字体尺寸、字体颜色。

<font size="3" color="red">This is some text!</font>
<font size="2" color="blue">This is some text!</font>
<font face="verdana" color="green">This is some text!</font>

🌷 新增编辑定义方法

   let Fun = null
      if (this.addForm.id) {
        Fun = editConference
      } else {
        Fun = addConference
      }
      Fun(this.addForm)
        .then(res => {
          this.show = false
          this.$emit('success', res.data)
          this.$message({
            type: 'success',
            message: '保存成功'
          })
        })

🌷 监听对象的某个值发生变化

watch: {
    postForm: {
      async handler(newVal) {
        this.initData()
      },
      immediate: true
    },

    'form.orgId': {
      async handler(newVal) {
        // 监听了再调用
        this.getList()
      },
      immediate: true
    }
  },

🌷 有接口的请求 用参数接收 可以转为同步。

 async getDetailList(id) {
      // if (!this.showMeetTab) return

      this.showMeetTab = true
      const { data } = await getConferenceById({
        id: id || this.baseMeetInfo.id,
        userId: localStorage.getItem('uid') || ''
      })

      this.setMeetData(data)
      clearInterval(this.timer)
      this.timer = null
      this.setTableData(id || this.baseMeetInfo.id)
    },

🌷刷新视图

//刷新视图
      this.$forceUpdate();

🌷 级联选择器 在选中节点改变时则只返回该节点的值

emitPath:false

  <el-cascader
                ref="cascader_Ref"
                v-model="form.leadDeptIds"
                :options="sortedTreeData"
                :props="{ multiple: true ,value:'id',label:'name',emitPath:false}"
                filterable
                collapse-tags
                style="width: 100%;"
                @change="handleChange"
              />

🌷 图片悬浮放大效果

 .tzico {
                width: 17px;
                height: 11px;
                margin-top: 15px;
                background: url('~@/assets/images/cms/right-arrow.png') no-repeat;

                // 悬浮放大效果
                &:hover {
                  -webkit-transform: scale(1.4);
                  -moz-transform: scale(1.4);
                  -ms-transform: scale(1.4);
                  -o-transform: scale(1.4);
                  transform: scale(1.4);
                }
              }

🌷图片从底部开始加载

background: url('~@/assets/images/cms/nr-bg.jpg') bottom no-repeat;

🌷数据不是键值对格式,只有参数值

export function getWeChatDetail(data) {
  return request({
    baseURL,
    url: '',
    method: 'get',
    // 数据不是键值对格式,只有参数值
    // headers: { 'Content-Type': 'application/json' },
    params: data
  })
}

🌷 vscode 终端加载慢

“terminal.integrated.defaultProfile.windows”: “Command Prompt”
在这里插入图片描述

🌷 滚动条样式

 //全局滚动条
  ::-webkit-scrollbar {
    width: 4px;
    height: 8px;
  }

  ::-webkit-scrollbar-thumb {
    border-radius: 5px;
    background-color: #45c2ff;
  }

  ::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px #007ac5;
    background: #007ac5;
    border-radius: 5px;
  }

🌷 flex 表格布局

 display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 5px;

🌷 文字乱码 不能复制有格式的文字 比如pdf 要清楚格式再复制

🌷 默认函数的参数 解构出来

 @change="(value)=>checkItem(value, item)"

🌷 table原生写法

 <table border="1" cellspacing="0" cellpadding="0" style="border-color: #2b82d9;" class="mr-table">
          <thead>
            <th colspan="2">用地类型</th>
            <th>用地面积</th>
          </thead>
          <tr v-for="(item,index) in baseList" :key="index">
            <td>{{ item.name }}</td>
            <td>{{ item.code }}</td>
            <td>{{ item.value }}</td>
          </tr>
          <tr>
            <td colspan="2">合计</td>
            <td>256.9</td>
          </tr>
        </table>

🌷 新增编辑定义方法

let Fun = null
      if (this.addForm.id) {
        Fun = editConference
      } else {
        Fun = addConference
      }
      Fun(this.addForm)
        .then(res => {
          this.show = false
          this.$emit('success', res.data)
          this.$message({
            type: 'success',
            message: '保存成功'
          })
        })
        .catch(err => {
          //关闭按钮禁用
          this.adding = false
          this.$message({
            type: 'error',
            message: err
          })
        })

🌷 html代码里 不能使用window

 <div class="text-2">
                      {{  (window.config.defaultPerson[localStorage.getItem('orgId')]) }}
                    </div>

只能在data里定义 在使用

 <div class="text-2">
                      {{ defaultPerson }}
  </div>
  data() {
    return {
		defaultPerson: (window.config.defaultPerson[localStorage.getItem('orgId')] || '待定')
	}
}

🌷 vue 挂载动态组件 或者 动态的html内容 滚动到底部

import PieBox from './components/PieBox.vue'
import LineBox from './components/LineBox.vue'
import BarBox from './components/BarBox.vue'
//方法
sendBarBox() {
      const _this = this
      const Profile = Vue.extend({
        components: { BarBox, PieBox, LineBox, KongBox },
        data: function() {
          return {
            tableList: _this.baseList,
            chartType: _this.chartType
          }
        },
        template: `
        <PieBox  v-if="chartType == 'pie'" :table-list="tableList" />
        <BarBox  v-else-if="chartType == 'bar'" :table-list="tableList" />
        <LineBox v-else-if="chartType == 'line'" :table-list="tableList" />
        <KongBox v-else  />
        `
      })
      const node = document.createElement('div')
      document.querySelector('#XXContent').appendChild(node)
      new Profile().$mount(node)
      // 滚动到底部
      this.$nextTick(() => {
        // 刷新视图
        const nodeList = document.querySelectorAll('.cb-left') || []
        if (nodeList.length) {
          const length = nodeList.length - 1
          document.querySelectorAll('.cb-left')[length].scrollIntoView()
        }
      })
    },

🌷 备份原来分支代码

1.commit 选择分支 右键revert commit
2.选择 hard
3.新建分支 发布
4.切回原分支
5,拉回代码

🌷组成树结构

 //处理树形结构
    tranListToTreeData(list) {
      const mapObj = {};
      const newArr = [];
      list.forEach((item) => {
        if (!item.children) {
          item.children = [];
        }
        mapObj[item.id] = item;
      });
      list.forEach((item) => {
        if (mapObj[item.parentId]) {
          mapObj[item.parentId].children.push(item);
        } else {
          newArr.push(item);
        }
      });
      return newArr;
    },

🌷 表格动态设置高度和最大高度

 <div class="content box-content">
 <el-table ref="commonDataRef" v-loading="loading" height="200px" :data="tableData" border>
 ...
 </el-table>
 </div>

async getList() {
      this.loading = true
      const { data } = await mountedPageList({
        current: this.currentPage,
        size: this.pageSize,
        ...this.searchForm
      })
      this.tableData = data.list
      this.total = data.total
      // 计算高度
      this.$nextTick(() => {
        const el = this.$refs.commonDataRef.$el
        if (!el) return
        const elBody = el.querySelector('.el-table__body')
        const elHeader = el.querySelector('.el-table__header-wrapper')
        const height = document.querySelector('.box-content').offsetHeight - 200
        if (elBody.offsetHeight < height) {
          this.$refs.commonDataRef.$el.style.height = `${elBody.offsetHeight + elHeader.offsetHeight + 2}px`
          this.$refs.commonDataRef.doLayout()
        } else {
          this.$refs.commonDataRef.$el.style.height = `${height}px`
          this.$refs.commonDataRef.doLayout()
        }
      })
      this.loading = false
    },

🌷 el-input事件

<el-input
	v-model="filterText"
	style="width:160px"
	placeholder="请输入名称"
	clearable
	@clear="changeFilterText"
	@keyup.native.enter="changeFilterText"
/>

🌷iframe url不刷新

 <iframe
                    id="Sell"
                    :key="row['链接地址']?row['链接地址']:url"
                    ref="Sell"
                    :style="{ width: '100%', height: '100%', border: '0' }"
                    :src="row['链接地址']?row['链接地址']:url"
                  />

🌷 数据试图 传参数排序

// 字段名: 数据视图返回的字段的名字 不是参数名
// 数据视图单个排序
sqlOrder:'age asc'
// 数据视图 多个排序
sqlOrder:'order by age asc,name desc'

🌷 地块定位

<plan-map
                  ref="plan-map"
                  class="plan-map"
                  env="prod"
                  token-key="GTKJ-Token"
                  :app-id="appId"
                  :area-code="areaCode"
                  :is-need-role="false"
                  :service-config="serviceConfig"
                  :tool-components="toolComponents"
                  @view-loaded="onViewLoaded"
                />

 onViewLoaded() {
      window.planMap = this.$planMap
      // window.planMap.mapComponents[0].enableClickQuery = this.fullScreen
      // this.maploaded = true
      // graphicsLayer = new window.Esri.GraphicsLayer({
      //   id: 'area-layer',
      //   title: '区县定位',
      //   listMode: 'hide'
      // })
      // window.planMap.addEsriLayerToMap(graphicsLayer)
      // this.doCount()
      // this.getTree().then(() => {
      //   const layerSource = window.planMap.serviceStore.query({
      //     id: '8d1c1e82-810a-4af3-b0bd-d57b5c02fa19'
      //   })[0]
      //   if (layerSource) {
      //     layerSource.checked = true
      //     this.onSwitchCheckedChange(true, layerSource)
      //   }
      // })
      // setTimeout(() => {
      //   if (this.areaName) {
      //     this.locateByAreaName(this.areaName)
      //     this.doCount()
      //   }
      // }, 1000)
      const list = [
        '渝中区',
        '大渡口区',
        '江北区',
        '沙坪坝区',
        '九龙坡区',
        '南岸区',
        '北碚区',
        '渝北区',
        '巴南区',
        '两江新区',
        '高新区'
      ]
      // 如果是中心城区为0 其他区县为 1
      const type = list.includes(this.row['行政区域']) ? 0 : 1
      this.$planMap.queryByUrlAndHighlight('http://23.36.123.131:10000/multApp/datamanager/service/a1c3e189-23d1-4d6a-8753-feac348a3090/b9444720-61ae-42e3-a74d-b8d93f305cbb/2ff26fb9-dbc1-4540-a54f-5437dd9756b8/MapServer/' + type, {
        where: `行政区域='${this.row.行政区域}' and 地块编号='${this.row.地块编号}'`,
        returnGeometry: true
      }, true)
    },

🌷 数组排序

// 数组按照某一字段名排序

 sortKey(array, key, sort) {
      return array.sort(function(a, b) {
        var x = a[key]
        var y = b[key]
        if (sort) {
          return x < y ? -1 : x > y ? 1 : 0
        } else {
          return x > y ? -1 : x < y ? 1 : 0
        }
      })
    },

🌷 接口方法名 动态设置 ,用于新增修改方法名不一致,但逻辑一样

// user login

  login(userInfo) {
      (userInfo.authCode ? authCodeLogin : userLogin)(userInfo)
        .then(response => {
        }).catch(error => {
        })
  },

🌷 对象结构 增加参数

export function authCodeLogin(data) {
  return request({
    url: '/authserver/user/spatial/authcode/login',
    method: 'post',
    data: {
      ...data,
      appId: 123
    }
  })
}

🌷 配置图片代理

(1)本地代理:vue.config.js 》module.exports

devServer: {
    port: port,
    open: false,
    overlay: {
      warnings: true,
      errors: true
    },
    proxy: {
      '/massifImg': {
        // 末尾不用/
        target: 'http://10.0.250.110/html/chanyeyongdi',
        pathRewrite: { '^/massifImg': '' }
      }
    }
  
  },

(2)服务器代理

prod-8010

server {
    listen       8010;
    server_name  localhost;

    #代理缓冲区设置
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 2 4k;
    proxy_busy_buffers_size 4k;
    proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
    proxy_max_temp_file_size 20M;
    proxy_temp_file_write_size 8k;

    #请求体最大数
    client_max_body_size 1024M;
    #请求头总长度大于128k时使用large_client_header_buffers设置的缓存区
    client_header_buffer_size 128k;
    #large_client_header_buffers 指令参数4为个数,128k为大小,默认是8k。申请4个128k。
    large_client_header_buffers 4 128k;

    add_header Cache-Control no-cache;
    add_header Cache-Control private;

    # add_header 'Access-Control-Allow-Origin' '*';
    # add_header 'Access-Control-Allow-Credentials' 'true';

    location / {
        root   /usr/share/nginx/prod/html/;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html last;
    }
     location /massifImg/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;  #获取首页一图irs统计数
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://10.0.250.110/html/chanyeyongdi/;
        # 末尾是 / 
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

(3)配置docker

COPY /zip/production/default.conf /etc/nginx/conf.d/

FROM 23.36.123.127:5000/xxzx_nginx:1.23.1

COPY /zip/production/ /usr/share/nginx/prod/html/

COPY /zip/production/default.conf /etc/nginx/conf.d/

(4)调用代理地址

data里定义    imgApi: /massifImg,
 <img
	 :src="`${imgApi}/${realImgName(item['唯一编号'])}.jpg`"
	    alt=""
	    height="200px"
  />


(5)修改代理后,一定要重启 ,不然不会生效

🌷 autofit 页面自适应

(1)安装依赖

"autofit.js": "^3.0.4",

 npm i autofit.js@3.0.4

(2)App.vue 挂载autofit

import autofit from 'autofit.js'
export default {
  name: 'App',
  mounted() {
    autofit.init({
      dh: 1080,
      dw: 1920,
      ignore: [
        {
          el: '.plan-map-warpper'
        }
      ],
      resize: true
    })
  }
}

#app {
  position: relative;
  overflow: hidden;
}

(3)调用的页面

mounted() {
    this.$nextTick(() => {
      this.resize()
    })
   
  },

 resize() {

      const transform = document.getElementById('app').style.transform
      if (transform) {
        const scale = Number(transform.split('(')[1].split(')')[0])
        const mapDom = document.querySelector('.plan-map-warpper')
        if (mapDom) {
          // mapDom.style.transform = `scale(${1 / scale},${1 / scale})`
          mapDom.style['transform-origin'] = 'left top'
          mapDom.style.width = `calc(100% * ${scale})`
          // mapDom.style.height = `calc(100% * ${scale})` //外层是100% 
          mapDom.style.height = 400 * scale + 'px'
        }
      }
    },

🌷 vue 3 deep写法

:deep(.el-table)

🌷 css 文字渐变色

 color: transparent;
      -webkit-background-clip: text;
      background-image: linear-gradient(
        180deg,
        #ffffff,
        #85d4ff
      );

🌷 vue2 使用js 模拟数据

(1)data.js  可导入多个

export const tabelObj =[]
export const tabelOb1j =[]
export const tabelOb3j =[]

(2)调用

import { tabelObj } from './data.js'

     const res = tabelObj
      this.tableData = res.data.elems || []
      this.total = 100

🌷 echarts 鼠标悬浮弹窗 限制在容器内

confine: true, // 限制tootip在容器内

tooltip: {
      trigger: 'axis',
       confine: true, // 限制tootip在容器内
       axisPointer: {
         lineStyle: {
           color: '#fff',
           type: 'line'
         }
       }
    }

🌷 掐头去尾 设置中间元素的间距

&.ic-item + .ic-item {
margin-top: 11px;
}

.ic-item {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 0px;
        text-align: center;
        cursor: pointer;
        &.ic-item + .ic-item {
          margin-top: 11px;
        }
 }

🌷 表格布局 行 高度 自适应

grid-auto-rows: auto;
或者设置 grid-auto-rows: 50%;
grid-gap 为间距

 display: grid;
      grid-template-columns: 1fr;
      grid-gap: 0px;
      height: 100%;
      grid-auto-rows: auto;
      

🌷 npm时出现SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve错误

当使用npm运行vue项目时,出现了错误,是由于自身node版本太低和package.json 里scripts设置了版本兼容高版本。

1,将package.json中“SET NODE_OPTIONS=–openssl-legacy-provider && ”删除

将"dev": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
替换成:
"dev": "vue-cli-service serve", 

🌷下载文件excel

// (1)
@click="download(`${downSrc}${param.instanceId}`)"

// (2)
import axios from 'axios'
import { getToken } from '@/utils/auth'
// (3)
  download(url) {
      axios({
        url,
        method: 'get',
        headers: {
          Authorization: getToken()
        },
        responseType: 'blob'

      })
        .then((res) => {
          const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
          const link = document.createElement('a')
          link.href = window.URL.createObjectURL(blob)
          link.download = '模板.xlsx'
          const evt = document.createEvent('MouseEvents')
          evt.initEvent('click', true, true)
          link.dispatchEvent(evt)
        })
        .catch(() => {
          this.$message.error('下载失败!')
        })
    },

🌷 vue3 父组件调用子组件方法

// 1 子 组件

<template>
	<div>我是子组件</div>
</template>
 
<script lang="ts" setup>
	// 第一步:定义子组件的方法
	const hello = (str: string) => {
		console.log('子组件的hello方法执行了--' + str)
	}
	// 第二部:暴露方法
	defineExpose({
		hello
	})
</script>

// 2.父组件

<template>
	<button @click="getChild">触发子组件方法</button>
	<!-- 一:定义 ref -->
	<Child ref="childRef"></Child>
</template>
 
<script lang="ts" setup>
	import { ref } from 'vue';
	import Child from '../../components/child.vue';
 
	// 二:定义与 ref 同名变量
	const childRef = ref <any> ()
 
	// 三、函数
	const getChild = () => {
		// 调用子组件的方法或者变量,通过value
		childRef.value.hello("hello world!");
	}
</script>

🌷 vue3 子组件发送事件给父组件

// 1 父组件
<template>
	<Child @sayHello="handle"></Child>
</template>
 
<script lang="ts" setup>
	import Child from '../../components/child.vue';
 
	const handle = () => {
		console.log('子组件调用了父组件的方法')
	}
</script>


// 2.子组件
<template>
	<view>我是子组件</view>
	<button @click="say">调用父组件的方法</button>
</template>
 
<script lang="ts" setup>
	const emit = defineEmits(["sayHello"])
 
	const say = () => {
		emit('sayHello')
	}
</script>

🌷 第一个参数不需要 就要下划线

data.filter((_, index) => {})

🌷 vue2 vue 3代理

proxy: {
      // [process.env.VUE_APP_BASE_API]: {
      //   target: `http://127.0.0.1:${port}/mock`,
      //   changeOrigin: true,
      //   pathRewrite: {
      //     ['^' + process.env.VUE_APP_BASE_API]: ''
      //   }
      // }
      '/DataMangerAPI': {
        target: 'http://23.36.2.150:9999/api/',
        changeOrigin: true,
        pathRewrite: { '^/DataMangerAPI': '' }
        // rewrite: (path) => path.replace(/^\/DataMangerAPI/, '')
      }
    }
    // before: process.env.NODE_ENV === 'development' ? require('./mock/mock-server.js') : ''
  },

🌷 数值保留2位小数,整数就是不保留小数位

let num = 3.14159;
let roundedNum = Math.round(num * 100) / 100; // 3.14

🌷 删除对象 或者数组

this.$delete(this.editForm, 'majorInfoList')

🌷 nvs 切换版本 pnpm安装依赖

管理员运行vscode
nvs list 
nvs use 具体版本

npm i -g pnpm 
pnpm i

🌷 \n换行

利用正则将html的\n换成<br>

<div v-else v-html="`${item.answer}`.replace(/\n/g,'<br/>')"></div>

2.css样式

<div v-else v-html="`${item.answer}`" style="white-space:pre-line;"></div>

🌷 element函数自带参数,增加参数

@command="changeName($event, item)" 

@command="(path) => changeName(path, item)"

🌷获取第三方链接重定向参数值

parseQueryParams(url: string) {
  const queryParams = {} as ParamsType;
  if(!url) { return queryParams}
  const searchParams = new URLSearchParams(url.split('?')[1] || '');
  for (const [key, value] of searchParams.entries()) {
    queryParams[key] = value;
  }
  return queryParams;
}

const queryParams = parseQueryParams(route.query?.redirect)
queryParams.areaCode 
   

🌷 淘宝镜像到期如何切换新镜像

清空缓存:npm cache clean --force
切换镜像源:npm config set registry https://registry.npmmirror.com
切换cnpm镜像:npm install -g cnpm --registry=https://registry.npmmirror.com
查看cnpm版本及镜像是否安装成功:cnpm -v
查看npm镜像是否配置成功:npm config get registry

🌷 文字渐变色

  background-image: -webkit-gradient(
        linear,
        left top,
        left bottom,
        from(#FFFFFF),
        to(#61D2F3)
      );
      /* background-image: -webkit-gradient(linear, left 0, right 0, from(rgb(166, 4, 249)), to(rgb(251, 223, 11))); */
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;

🌷 前端导出excel

npm install xlsx file-saver


<template>
  <button @click="exportToExcel">导出Excel</button>
</template>
 

<script>
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
 
export default {
  methods: {
    exportToExcel() {
      // 假设你有一个表格数据的数组
      const data = [
        ["姓名", "年龄", "职业"],
        ["Alice", 28, "Engineer"],
        ["Bob", 22, "Designer"]
      ];
 
      // 将数据转换为工作表
      const worksheet = XLSX.utils.aoa_to_sheet(data);
 
      // 创建工作簿并添加工作表
      const workbook = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
 
      // 生成Excel文件
      const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
 
      // 使用blob和FileReader创建一个URL然后下载
      const dataBlob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
      saveAs(dataBlob, 'export.xlsx');
    }
  }
};
</script>

🌷前端多个请求全部返回后再处理数据

promises为数组

 handle() {
      this.loading = true
      const promises = []
      promises.push(this.getRowDetail().then(res => {
        this.detailsList = res
      }))

      promises.push(this.getTableHeaderList())

      Promise.all(promises).then(res => {
        this.exportTable()
      }).catch(() => {
        this.loading = false
      })
    },
    // 获取详情
    getRowDetail() {
      return detailsList({ typeUuid: this.form.typeUuid }).then(res => {
        const list = res.data || []
        list.forEach(item => {
          const data = JSON.parse(item.data)
          item.details = this.handleKey(data)
        })
        return list
      }).catch(err => {
        this.$message.error(err)
      })
    },
    getTableHeaderList() {
      return contentList({ uuid: this.form.typeUuid }).then(res => {
        if (res.data) {
          const list = res.data || []
          this.tableHeader = this.handleKey(list)
          return
        }
      }).catch(err => {
        this.$message.error(err)
      })
    },

🌷替换字符串,全部

let newStr = str.replaceAll('JS','JavaScript');

🌷获取某个节点下的所有th节点

const array = this.$refs.QRTable.getElementsByTagName('th')

🌷css手写箭头

官网:https://www.jiangweishan.com/tool/clippy/
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 100%, 50% 50%, 0% 0%);
-webkit-clip-path:polygon(50% 0%, 100% 50%, 50% 100%, 0% 100%, 50% 50%, 0% 0%);

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .part {
        display: flex;
      }
      .item {
        width: 200px;
        height: 50px;
        /* border: 1px solid #bbb; */
        position: relative;

      }
      .item:hover {
        background-color: lightblue;
      }
      .item + .item {
        /* margin-left: 20px; */
      }
      .item + .item::before {
        content: " ";
        position: absolute;
        width: 30px;
        height: 50px;
        clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 100%, 50% 50%, 0% 0%);
        -webkit-clip-path:polygon(50% 0%, 100% 50%, 50% 100%, 0% 100%, 50% 50%, 0% 0%);
        background-color: #fff;
        left: -15px;
        z-index: 1;
      }
      .red {
        background-color: red;
      }
      .blue {
        background-color: blue;
      }
      .green {
        background-color: green;
      }
    </style>
  </head>
  <body>
    <div class="part">
      <div class="item red"></div>
      <div class="item blue"></div>
      <div class="item green"></div>
    </div>
  </body>
</html>

🌷 Vue3 echarts tooltip不生效

Vue3 底层使用了 proxy 代理创建实例,其创建出来的实例与echarts真正使用的那个存在兼容性问题,所以Echarts 无法从中获取内部变量;故设置echarts实例时,不要使用ref、reactive等响应式方法创建echarts对象,应该使用shallowReactive、shallowRef、或者普通变量即可

🌷 去除echarts图表中的条纹背景色

如果是横向条纹,如上图,就在yAxis中添加splitArea:false
如果是竖向条纹,就将这句代码加在xAxis里

在这里插入图片描述

🌷 动态设置class

第一种:对象的形式: 用花括号包裹起来,类名用引号,可添加多个class

<p :class="{'p1' : false, 'p': true}">
第二种:三元表达式 注意点:放在数组中,类名要用引号

<p :class="[ 1 < 2 ? 'p1' : 'p' ]" ></p>
第三种:数组的形式

<p :class="[isTrue, isFalse]"></p>
第四种:数组中使用对象

<p :class="[{'p1': false}, isFalse]"></p>
第五种:通过函数返回对应的class名字

<p :class="setClass"></p>
第六种:在原有的class基础上再加class 

<div :class="['active','on',seckillProfit>=0?'green':'red ']">{{seckillProfit}}</div>
   原本就有 sctive、on,两个class,再根据 seckillProfit 值动态加green / red 



<script>
    export default {
        data () {
           return {
               isTrue: 'p1',
               isFalse: 'p'
           };
        },
  method: {
		  setclass () {
		        return 'p1';
		      }
		  }
    }
</script>

🌷 css 滤镜 filter 属性

filter:blur(4px);//模糊
filter:brightness(2);//亮度,默认是1。可以使用百分比也可以使用小数表示。
filter:contrast(2);//对比度,默认是1。可以使用百分比也可以使用小数表示。
filter:drop-shadow(2px 10px 0 rgba(255,0,0,0.5));//投影,(x偏移  y偏移   模糊范围   颜色)
filter:grayscale(0.5);//灰度,0~1,0%~100%
filter:hue-rotate(125deg);//色相旋转,让图像中的颜色,在色相环中做对应的旋转。
filter:invert(100%);//反转图像,黑变白,白变黑
filter:opacity(0.5);//透明度
filter:saturate(200%);//饱和度
filter:sepia(100%);//转为褐色,值为100%则完全是深褐色的,值为0%图像无变化。

🌷 图片从右侧开始加载,

下部加载 bottom 以此类推

background: url('~@/assets/home/tu/bg4.png') right no-repeat;

🌷 聚合数据

data.list
.filter(
      item => item['原因分类'] === '开发意愿低'
    ).reduce((acc, curr) => acc + Number(curr['数据值']), 0),

🌷 表格 合并某一列相同字段


<el-table
      v-loading="loading"
      :data="dataSetList"
      border
      tooltip-effect="dark"
      :size="tableSize"
      :height="tableHeight"
      style="width: 100%; margin: 15px 0"
      :span-method="genderSpanCity"
    >

   //合并单元格----------------------
    genderSpanCity({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 ) {
        // 获取当前单元格的值
        const currentValue = row["warnGroup"];
        // 获取上一行相同列的值
        const preRow = this.dataSetList[rowIndex - 1];
        const preValue = preRow ? preRow["warnGroup"] : null;
        // 如果当前值和上一行的值相同,则将当前单元格隐藏
        if (currentValue === preValue) {
          return { rowspan: 0, colspan: 0 };
        } else {
          // 否则计算当前单元格应该跨越多少行
          let rowspan = 1;
          for (let i = rowIndex + 1; i < this.dataSetList.length; i++) {
            const nextRow = this.dataSetList[i];
            const nextValue = nextRow["warnGroup"];
            if (nextValue === currentValue) {
              rowspan++;
            } else {
              break;
            }
          }
          return { rowspan, colspan: 1 };
        }
      }
    },

🌷 echarts tooltip 内容置顶

tooltip: {
                trigger: 'item',
                // extraCssText:'z-index:9999'
                appendToBody: true

              },

🌷 定位居中

外层相对定位。里面绝对定位
left: 50%;
transform: translateX(-50%);

.父元素{
 position: relative;
 }
.子元素{
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 30px;
}

🌷宽度随容器自适应

width: fit-content;

🌷倒起的小三角 (下三角)

.arrow-box {
      display: flex;
      justify-content: center;
      .arrow {
        -webkit-clip-path: polygon(51% 38%, 0% 100%, 100% 100%);
        clip-path: polygon(51% 38%, 0% 100%, 100% 100%);
        background: #0b3e79;
        width: 20px;
        height: 20px;
      }

    }

🌷 echarts图例失真, 字体模糊

采用svg渲染,比canvans清晰度高

var myChart = echarts.init(document.getElementById(item.id), 'walden',{devicePixelRatio: 2});17:01

// 方法一:

this.chart = this.$echarts.init(document.getElementById('id'), null, {renderer: 'svg'}) // 采用svg渲染,比canvans清晰度高

// 方法二:
this.chart = this.$echarts.init(document.getElementById('id'), null, {devicePixelRatio: 2.5}) // 采用canvans渲染,devicePixelRatio调整清晰度

🌷git 配置ssh key

1.setting>>ssk key
2.点击 generate one
在这里插入图片描述
3. cmd 打开终端,输入

ssh-keygen -t ed25519 -C "email@example.com"

4.一直回车,然后 复制文件地址,打开 id_ed25519.pub,
在这里插入图片描述
5.复制,粘贴再
在这里插入图片描述
6.在使用ssh拉取代码

🌷国土信息平台 链接新窗口打开

放在uip后面,不要编码
在这里插入图片描述

平台 加这个参数 &newwindow=newwindow

🌷 css文字渐变色

background-image: -webkit-gradient(
        linear,
        left top,
        left bottom,
        from(#1dc1e6),
        to(#068dfa)
      );
      /* background-image: -webkit-gradient(linear, left 0, right 0, from(rgb(166, 4, 249)), to(rgb(251, 223, 11))); */
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;

🌷装依赖的时候 要全部拷贝

“@riophae/vue-treeselect”: “^0.4.0”,
这种安装的时候:

 pnpm add @riophae/vue-treeselect 

pnpm 安装单个依赖 pnpm add
安装所有依赖 pnpm i

🌷v-html 渲染的内容

修改class样式,需要用deep找到class


 :deep(.unit) {
            font-size: 14px;
          }

🌷 数据在最前面插入一项数据

 this.unitTreeData.unshift({
          nodeName: '所有',
          nodeNum: XEUtils.sum(data, 'nodeNum'),
          children: data
        })

🌷css3动效

transition: transform 0.3s;

🌷函数某一个参数不传 _

 item.children.filter((_, i) => i < 6)

🌷 接口返回处理返回的数据,进行封装

在这里插入图片描述

🌷 组装三层树结构

function init() {
  // 处理底部数据
  getDataView('6434c615-1e73-05af-b9d6-9661f6363f0d').then((res) => {
    const bList = res.data.list;
    list.value = changeTree(bList)
    console.log("🚀 ~ getDataView ~ list.value:", list.value)

  });
}

function changeTree(data: any) {
  // 处理第一层数据
  let coreBusinesses: any = []
  data.map((item: any) => {
    coreBusinesses.push({
      name: item['一级分类'],
      children: []
    })
  })
  // 去重
  coreBusinesses = removeSame(coreBusinesses, 'name')

  // 循环第一层
  coreBusinesses.forEach((el1: any) => {
    // 处理第二层数据
    let firstLevelBusinesses: any = []
    // 找出所有的第二层数据
    const arr = data.filter(item => item['一级分类'] === el1.name)
    arr.forEach((row: any) => {
      firstLevelBusinesses.push({
        name: row['二级分类'],
        children: []
      })
    })
    // 去重
    firstLevelBusinesses = removeSame(firstLevelBusinesses, 'name')
    el1.children = firstLevelBusinesses || []

    // 处理第三层数据
    el1.children.forEach((el2: any) => {
      const arr3 = data.filter((item: any) => item['一级分类'] === el1.name && item['二级分类'] === el2.name)
      let secondLevelBusinesses: any = []
      arr3.forEach((row: any) => {
        secondLevelBusinesses.push({
          name: row['数据资源名称'],
          value: row['数值'],
          unit: row['单位']
        })
      })
      // 去重
      secondLevelBusinesses = removeSame(secondLevelBusinesses, 'name')
      el2.children = secondLevelBusinesses || []
    })
  })

  return coreBusinesses
}

function removeSame(arr: any, prop: string) {
  const map = new Map()
  return arr.filter((obj: any) => !map.has(obj[prop]) && map.set(obj[prop], true))
}

🌷el-tooltip 为空时 不显示悬浮

:visible=“isEffective(detail.advantage)”

<el-tooltip :content="detail.advantage" placement="top-start" :visible="isEffective(detail.advantage)" >
              <div class="warning-time">特色优势:{{ detail.advantage || '-' }}</div>
            </el-tooltip>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值