🌷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>