角色管理
清除表单上次校验
ts
// 创建按钮回调
const handleCreate = () => {
dialogVisible.value = true
formRef.value?.resetFields()
roleInfo.value.name = ''
roleInfo.value.remark = ''
roleInfo.value.id = ''
// 重置选中状态
setCurrent()
}
使用inport引入图片
ts
import deviceIcon from '@/assets/deviceicon.png';
const labelOptions = ref({
visible: true,
markerList: props.dataList,
icon: {
image: deviceIcon, // 引用已解析的图片路径
// anchor: 'bottom-center',
// size: [25, 34],
// clipOrigin: [459, 92],
// clipSize: [50, 68]
}
});
遍历获取需要属性
ts
// 处理数据-获取根节点数据
const filterMenuData = (original: any[]) => {
return original
.filter((item: any) => !item.pid) // 筛选 pid 为空的根节点
.map((item: any) => ({
id: item.id,
name: item.name,
pid: item.pid,
})); // 返回只包含 id、name、pid 的对象数组
};
// 示例数据
const originalData = [
{ id: 1, name: "根节点1", pid: null },
{ id: 2, name: "子节点1", pid: 1 },
{ id: 3, name: "根节点2", pid: null },
{ id: 4, name: "子节点2", pid: 3 },
];
// 调用函数
const rootNodes = filterMenuData(originalData);
console.log(rootNodes);
复制按钮动态显示
vue
<template>
<div class="copy-container">
<!-- 提示框 -->
<el-tooltip
content="点击复制"
placement="top"
v-if="!copied"
>
<!-- 未复制图标 -->
<el-icon
:class="['copy-icon', copied ? 'copied' : '']"
@click="handleCopy"
>
<copy-document />
</el-icon>
</el-tooltip>
<!-- 已复制的提示 -->
<el-tooltip
content="已复制!"
placement="top"
v-if="copied"
>
<el-icon
:class="['copy-icon', copied ? 'copied' : '']"
>
<check />
</el-icon>
</el-tooltip>
</div>
</template>
<script lang="ts">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { CopyDocument, Check } from "@element-plus/icons-vue";
export default {
components: {
CopyDocument,
Check,
},
setup() {
// 是否已复制的状态
const copied = ref(false);
// 处理复制逻辑
const handleCopy = () => {
// 模拟复制功能,可以替换为实际逻辑
const textToCopy = "要复制的内容";
navigator.clipboard.writeText(textToCopy).then(
() => {
copied.value = true;
ElMessage.success("复制成功!");
// 2秒后恢复为未复制状态
setTimeout(() => {
copied.value = false;
}, 2000);
},
() => {
ElMessage.error("复制失败,请重试!");
}
);
};
return {
copied,
handleCopy,
};
},
};
</script>
<style scoped>
.copy-container {
display: inline-flex;
align-items: center;
justify-content: center;
}
.copy-icon {
font-size: 24px;
cursor: pointer;
transition: transform 0.2s ease;
}
.copy-icon.copied {
color: green;
transform: scale(1.2);
}
</style>
ts
功能解析
图标动态切换
使用 copied 状态管理图标的显示。
根据状态,切换显示为未复制或已复制的图标。
复制功能
使用 navigator.clipboard.writeText 将文本写入剪贴板。
成功后,通过 copied 状态触发图标变化。
延迟恢复状态
使用 setTimeout 在 2 秒后将 copied 状态重置为 false。
样式动画
使用 CSS 的 transform 和 transition 增加用户交互的视觉效果。
提示信息
使用 ElMessage 显示操作反馈。
运行效果
点击图标时,文本被复制,图标变为已复制的状态,并且显示提示信息。
2 秒后,图标恢复为未复制状态,可以再次点击复制。
三元运算符
ts
简化写法
如果状态较少且逻辑简单,可以直接在模板中通过三元表达式实现:
<span>
{{ item.off === 0 ? item.property1 : item.off === 1 ? item.property2 : item.property3 }}
</span>
null的判断
ts
在你的代码中,item.off >= 0 表达式会导致 null 被隐式转换为 0,因为在 JavaScript 中,比较运算符 >= 会将 null 转换为数字 0,因此 null >= 0 的结果是 true
在 JavaScript 中,>= 会触发隐式类型转换:
如果 item.off 是 null,它会被转换为数字 0。
然后 0 >= 0 评估为 true,所以颜色被设置为绿色。
<span :style="{ color: item.off === null || item.off === undefined ? 'red' : item.off >= 0 ? 'green' : 'red', marginLeft: '1px' }">
{{ item.off }}
</span>
加载中骨架屏 栅格
<el-card>
之所以会纵向排列,是因为它们默认是以 块级元素(block-level element) 的方式排列的,也就是每个卡片占据一整行。为了让它们横向排列,需要使用 Flex 布局 或 Grid 布局 来控制其排列方式。
Element Plus 提供的栅格系统可以方便地实现横向排列。
vue
<el-skeleton class="skeleton-loading" v-show="deviceListLoading" animated style="width: 100%;">
<template #template>
<el-row :gutter="10">
<el-col :span="6" v-for="(_, index) in 12" :key="index">
<el-card style="border-radius: 5px;">Card {{ index + 1 }}</el-card>
</el-col>
</el-row>
</template>
</el-skeleton>
pinia
计算属性
你的代码中,Pinia
的 getters
用来计算基于 state
的值。在你的需求中,当 state
中的 sn
不存在时,可以从 localStorage
的 para
获取数据并更新 state
中的 sn
。但你的实现中有些问题,例如直接修改 state.sn
是不被推荐的,因为 getters
是计算属性,不应该直接修改状态。
ts
import { defineStore } from 'pinia';
export const useDeviceStore = defineStore('device', {
state: () => ({
sn: '', // 初始化 sn
}),
getters: {
getDeviceInfo(state) {
// 如果 state.sn 不存在,尝试从 localStorage 中获取 para 并解析
if (!state.sn) {
const para = JSON.parse(localStorage.getItem('para') || '{}');
if (para.sn) {
state.sn = para.sn; // 更新 state.sn
}
}
return state.sn; // 返回 sn
},
},
});
getters
的职责:
getters
的目的是返回计算后的值,避免直接修改state
。- 但在你的需求中,需要动态从
localStorage
获取数据并更新state.sn
,因此可以在getters
中进行条件处理。
localStorage
的解析:
- 使用
JSON.parse
安全地解析localStorage
中的数据,同时提供默认值{}
,以避免解析出错。
Pinia 响应式支持:
- 当
state.sn
更新时,Pinia 会自动触发响应式更新。
更清晰的逻辑分离
ts
export const useDeviceStore = defineStore('device', {
state: () => ({
sn: '',
}),
actions: {
loadDeviceInfo() {
if (!this.sn) {
const para = JSON.parse(localStorage.getItem('para') || '{}');
if (para.sn) {
this.sn = para.sn;
}
}
},
},
getters: {
getDeviceInfo: (state) => state.sn, // 仅返回 sn
},
});
ts
使用时:
const store = useDeviceStore();
store.loadDeviceInfo(); // 先调用 action 加载数据
console.log(store.getDeviceInfo); // 获取 sn
动态导航栏
ts
在 Vue 3 + TypeScript 项目中,可以通过一个动态组件来实现一个功能性的页面导航栏,类似于浏览器的标签页。以下是具体实现思路和代码示例:
实现功能描述
显示当前页面:展示当前页面的名称。
切换页面:点击某个页面标签,可以切换到对应的页面。
关闭页面:在标签上添加关闭按钮,可以关闭对应的页面。
复制文本
vue
<template>
<div>
<!-- 可复制的文本 -->
<p @dblclick="copyText" ref="textElement">双击我复制这段文本!</p>
<!-- 显示复制状态 -->
<p v-if="copySuccess" class="success-message">复制成功!</p>
</div>
</template>
<script lang="ts">
import { ref } from "vue";
export default {
name: "CopyText",
setup() {
// 引用目标文本元素
const textElement = ref<HTMLParagraphElement | null>(null);
// 复制成功状态
const copySuccess = ref(false);
// 双击复制文本的函数
const copyText = async () => {
if (textElement.value) {
const text = textElement.value.innerText;
// 尝试使用 Clipboard API
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(text);
showSuccessMessage();
return;
} catch (error) {
console.error("Clipboard API 复制失败:", error);
}
}
// 回退到 execCommand 方法
try {
const textarea = document.createElement("textarea");
textarea.value = text;
// 隐藏 textarea 并添加到文档中
textarea.style.position = "absolute";
textarea.style.left = "-9999px";
document.body.appendChild(textarea);
// 选中并复制内容
textarea.select();
const successful = document.execCommand("copy");
document.body.removeChild(textarea);
if (successful) {
showSuccessMessage();
} else {
console.error("execCommand 复制失败");
}
} catch (error) {
console.error("execCommand 方法复制失败:", error);
}
}
};
// 显示复制成功提示
const showSuccessMessage = () => {
copySuccess.value = true;
setTimeout(() => {
copySuccess.value = false;
}, 2000);
};
return {
textElement,
copyText,
copySuccess,
};
},
};
</script>
<style scoped>
.success-message {
color: green;
font-weight: bold;
}
</style>
svg-icon
ts
从代码来看,你的目标是全局注册 Element Plus 的图标组件,同时集成一个自定义的 SvgIcon 组件来加载自定义的 SVG 图标。下面是代码的详细说明以及可能的优化点:
ts
const icons = svg as any;
for (const i in icons) {
app.component(`ele-${icons[i].name}`, icons[i]);
}
这段代码会将 @element-plus/icons-vue 中的所有图标组件以 ele- 为前缀注册为全局组件,例如 ele-Edit, ele-Search。
ts
该组件的功能是根据传入的 name 动态显示不同来源的图标,包括:
Element Plus 的内置图标:
图标名称以 ele- 开头,使用 <component> 动态渲染。
用于渲染 @element-plus/icons-vue 中的图标。
外部链接或本地图片图标:
图标名称以 https, http, /src, /assets 等路径开头时,使用 <img> 标签渲染图标。
自定义 CSS 类图标:
默认通过 <i> 标签渲染其他类型的图标(通常用于字体图标,如 Font Awesome)。
支持的样式配置:
支持通过 size 和 color 属性调整图标大小和颜色。
vue
<template>
<i v-if="isShowIconSvg" class="el-icon" :style="setIconSvgStyle">
<component :is="getIconName" />
</i>
<div v-else-if="isShowIconImg" :style="setIconImgOutStyle">
<img :src="getIconName" :style="setIconSvgInsStyle" />
</div>
<i v-else :class="getIconName" :style="setIconSvgStyle" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
export default defineComponent({
name: 'svgIcon',
props: {
name: {
type: String,
required: true,
},
size: {
type: Number,
default: 14,
},
color: {
type: String,
default: '#000',
},
},
setup(props) {
// 用于判断图标类型
const isShowIconSvg = computed(() => props.name?.startsWith('ele-'));
const isShowIconImg = computed(() => /^(https?:\/\/|\/src|\/assets)/.test(props.name || ''));
// 获取图标名称
const getIconName = computed(() => props.name || '');
// 样式设置
const setIconSvgStyle = computed(() => `font-size: ${props.size}px; color: ${props.color};`);
const setIconImgOutStyle = computed(() => `width: ${props.size}px; height: ${props.size}px; display: inline-block;`);
const setIconSvgInsStyle = computed(() => `width: ${props.size}px; height: ${props.size}px;`);
return {
isShowIconSvg,
isShowIconImg,
getIconName,
setIconSvgStyle,
setIconImgOutStyle,
setIconSvgInsStyle,
};
},
});
</script>
使用方式
ts
使用 Element Plus 图标:
<svg-icon name="ele-Edit" size="24" color="#409EFF" />
使用外部或本地图片:
<svg-icon name="https://example.com/icon.svg" size="32" />
使用自定义类名图标:
<svg-icon name="custom-icon-class" size="16" color="red" />
要在 Element Plus
的 <el-button>
中使用自定义图标,并结合你的 svg-icon
组件,关键在于将 svg-icon
作为按钮的图标插槽来使用。
vue
<template>
<!-- 使用自定义 svg-icon 作为按钮的图标 -->
<el-button type="primary" circle>
<svg-icon name="ele-Edit" size="20" color="#fff" />
</el-button>
<el-button type="success" circle>
<svg-icon name="custom-icon-class" size="20" color="#fff" />
</el-button>
<el-button type="warning" circle>
<svg-icon name="https://example.com/icon.svg" size="20" />
</el-button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
export default defineComponent({
name: 'CustomButton',
components: {
SvgIcon,
},
});
</script>
<style scoped>
/* 确保图标在按钮中居中显示 */
.el-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
}
</style>
动态设置图标
vue
<template>
<el-button type="primary" circle>
<svg-icon :name="iconName" :size="20" :color="iconColor" />
</el-button>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
export default defineComponent({
name: 'DynamicButtonIcon',
components: {
SvgIcon,
},
setup() {
const iconName = ref('ele-Edit'); // 动态图标名称
const iconColor = ref('#fff'); // 动态图标颜色
return {
iconName,
iconColor,
};
},
});
</script>
el-drawer隐藏滚动条
方式1
ts
/* 针对 el-Drawer 的滚动条隐藏但保留滚动功能 */
.el-drawer__body {
overflow-y: scroll; /* 保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
.el-drawer__body::-webkit-scrollbar {
width: 0; /* 隐藏滚动条 */
height: 0;
}
方式2通过 custom-class
添加自定义样式
如果只想对某个特定的 el-Drawer
生效,可以通过 custom-class
添加自定义样式:
vue
<template>
<el-drawer
title="示例"
:visible.sync="visible"
custom-class="no-scroll-drawer">
<p>内容1...</p>
<p>内容2...</p>
<p>内容3...</p>
</el-drawer>
</template>
<style>
/* 自定义样式 */
.no-scroll-drawer .el-drawer__body {
overflow-y: scroll; /* 保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
.no-scroll-drawer .el-drawer__body::-webkit-scrollbar {
width: 0; /* 隐藏滚动条 */
height: 0;
}
</style>
方式3 通过内联样式动态控制
可以在组件中通过 JavaScript 动态设置滚动条样式:
vue
<template>
<el-drawer
ref="drawer"
title="示例"
:visible.sync="visible">
<div class="content">
<p>内容1...</p>
<p>内容2...</p>
<p>内容3...</p>
</div>
</el-drawer>
</template>
<script>
import { ref, watch } from "vue";
export default {
setup() {
const visible = ref(false);
const drawer = ref(null);
watch(visible, (newVal) => {
if (newVal && drawer.value) {
const drawerBody = drawer.value.$el.querySelector(".el-drawer__body");
if (drawerBody) {
drawerBody.style.overflowY = "scroll"; // 保留滚动功能
drawerBody.style.scrollbarWidth = "none"; // 隐藏 Firefox 滚动条
drawerBody.style.msOverflowStyle = "none"; // 隐藏 IE/Edge 滚动条
drawerBody.style.webkitScrollbar = "none"; // 隐藏滚动条(兼容 Webkit)
}
}
});
return { visible, drawer };
},
};
</script>
<style>
/* 隐藏滚动条 */
.el-drawer__body::-webkit-scrollbar {
width: 0;
height: 0;
}
</style>
linux日志查询
cd /opt/temper/logs/process/info
ts
grep -C 10 '062005000279829' info.log
ts
按行显示匹配关键字并统计行数
grep "linux" example.txt | wc -l
高亮显示关键字并打印最后几行
grep --color=always "关键字" logfile.log | tail -n 5
动态查看日志内容
如果日志文件正在不断更新,并想实时查看包含关键字的最后几行,可以使用以下命令:
tail -f logfile.log | grep --color=always "关键字"
只打印文件末尾的日志并搜索关键字
如果日志文件非常大,可以直接从末尾开始搜索以提高效率:
tail -n 1000 logfile.log | grep --color=always "关键字" | tail -n 5
如果想在日志文件中查找某个错误信息,同时查看前后上下文
grep -C 3 "ERROR" logfile.log
想搜索某段代码中的关键字并查看附近代码片段:
grep -C 5 "function" script.js
索包含关键字(如 IP 地址或端口)的内容,并查看上下几行配置或状态信息
grep -C 2 "192.168.1.1" network.log
末尾几行
grep -C 10 '062005000279829' info.log
绝对值
ts
const validateY = (rule: any, value: any, callback: any) => {
if (Math.abs(value - RemoteAdjustForm.value.k) < 5) {
console.log('value',value)
callback(new Error('角色必须设置'))
} else {
callback(); // 验证通过
}
};
禁用按钮提示
要在按钮处于 disabled
状态时提示用户原因,你可以结合 Element-Plus
的 Tooltip
组件来实现。以下是一个完整的示例:
vue
<template>
<el-tooltip
v-if="RemoteAdjustForm.overtime === '0'"
content="当前状态无法提交"
effect="dark"
placement="top"
>
<el-button
type="primary"
@click="onRemoteAdjustSubmit"
:loading="RemoteAdjustLoading"
:disabled="RemoteAdjustForm.overtime === '0'"
>
{{ RemoteAdjustLoading ? '提交中' : '提交' }}
</el-button>
</el-tooltip>
<el-button
v-else
type="primary"
@click="onRemoteAdjustSubmit"
:loading="RemoteAdjustLoading"
>
{{ RemoteAdjustLoading ? '提交中' : '提交' }}
</el-button>
</template>
<script>
export default {
data() {
return {
RemoteAdjustLoading: false,
RemoteAdjustForm: {
overtime: '0', // 示例数据,表示禁用状态
},
};
},
methods: {
onRemoteAdjustSubmit() {
// 提交逻辑
console.log('提交表单');
},
},
};
</script>
获取当前页面的路由path
vue
<template>
<div>
<h1>当前页面路径</h1>
<p>当前路径: {{ currentPath }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'CurrentPath',
setup() {
const route = useRoute();
// 获取当前路由的 path
const currentPath = computed(() => route.path);
return {
currentPath,
};
},
});
</script>
lodash节流操作
vue
<template>
<div>
<el-button type="primary" @click="handleClick">节流按钮</el-button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { throttle } from 'lodash';
export default defineComponent({
name: 'ThrottleButton',
setup() {
// 定义节流的点击事件,设置节流间隔为 2 秒
const handleClick = throttle(() => {
console.log('按钮点击事件触发!');
}, 2000);
return {
handleClick,
};
},
});
</script>