Merge pull request #152 from diamont1001/dev
feat: 增加复制组件,解决 useClipboard 兼容性问题
This commit is contained in:
62
src/components/CopyButton/index.vue
Normal file
62
src/components/CopyButton/index.vue
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!-- 复制组件 -->
|
||||||
|
<template>
|
||||||
|
<el-button link @click="handleClipboard" :style="style">
|
||||||
|
<slot>
|
||||||
|
<el-icon><DocumentCopy color="var(--el-color-primary)" /></el-icon>
|
||||||
|
</slot>
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineOptions({
|
||||||
|
name: "CopyButton",
|
||||||
|
inheritAttrs: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleClipboard() {
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
// 使用 Clipboard API
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(props.text)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success("Copy successfully");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
ElMessage.warning("Copy failed");
|
||||||
|
console.log("[CopyButton] Copy failed", error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 兼容性处理(useClipboard 有兼容性问题)
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.style.position = "absolute";
|
||||||
|
input.style.left = "-9999px";
|
||||||
|
input.setAttribute("value", props.text);
|
||||||
|
document.body.appendChild(input);
|
||||||
|
input.select();
|
||||||
|
try {
|
||||||
|
const successful = document.execCommand("copy");
|
||||||
|
if (successful) {
|
||||||
|
ElMessage.success("Copy successfully!");
|
||||||
|
} else {
|
||||||
|
ElMessage.warning("Copy failed!");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
ElMessage.error("Copy failed.");
|
||||||
|
console.log("[CopyButton] Copy failed.", err);
|
||||||
|
} finally {
|
||||||
|
document.body.removeChild(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
1
src/types/components.d.ts
vendored
1
src/types/components.d.ts
vendored
@@ -11,6 +11,7 @@ declare module "vue" {
|
|||||||
AppMain: (typeof import("./../layout/components/AppMain/index.vue"))["default"];
|
AppMain: (typeof import("./../layout/components/AppMain/index.vue"))["default"];
|
||||||
VisitTrend: (typeof import("./../views/dashboard/components/VisitTrend.vue"))["default"];
|
VisitTrend: (typeof import("./../views/dashboard/components/VisitTrend.vue"))["default"];
|
||||||
Breadcrumb: (typeof import("./../components/Breadcrumb/index.vue"))["default"];
|
Breadcrumb: (typeof import("./../components/Breadcrumb/index.vue"))["default"];
|
||||||
|
CopyButton: (typeof import("./../components/CopyButton/index.vue"))["default"];
|
||||||
CURD: (typeof import("./../components/CURD/index.vue"))["default"];
|
CURD: (typeof import("./../components/CURD/index.vue"))["default"];
|
||||||
DeptTree: (typeof import("./../views/system/user/components/dept-tree.vue"))["default"];
|
DeptTree: (typeof import("./../views/system/user/components/dept-tree.vue"))["default"];
|
||||||
UserImport: (typeof import("./../views/system/user/components/user-import.vue"))["default"];
|
UserImport: (typeof import("./../views/system/user/components/user-import.vue"))["default"];
|
||||||
|
|||||||
@@ -82,7 +82,14 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ label: "手机号码", align: "center", prop: "mobile", width: 120 },
|
{
|
||||||
|
label: "手机号码",
|
||||||
|
align: "center",
|
||||||
|
prop: "mobile",
|
||||||
|
templet: "custom",
|
||||||
|
slotName: "mobile",
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "状态",
|
label: "状态",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
|||||||
@@ -40,6 +40,14 @@
|
|||||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
<template #mobile="scope">
|
||||||
|
<el-text> {{ scope.row[scope.prop] }} </el-text>
|
||||||
|
<copy-button
|
||||||
|
v-if="scope.row[scope.prop]"
|
||||||
|
:text="scope.row[scope.prop]"
|
||||||
|
style="margin-left: 2px"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</page-content>
|
</page-content>
|
||||||
|
|
||||||
<!-- 新增 -->
|
<!-- 新增 -->
|
||||||
|
|||||||
@@ -3,43 +3,39 @@
|
|||||||
<el-tabs type="border-card">
|
<el-tabs type="border-card">
|
||||||
<el-tab-pane label="Icons">
|
<el-tab-pane label="Icons">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div
|
<div v-for="item of svg_icons" :key="item">
|
||||||
v-for="item of svg_icons"
|
<copy-button :text="generateIconCode(item)">
|
||||||
:key="item"
|
<el-tooltip
|
||||||
@click="handleClipboard(generateIconCode(item), $event)"
|
effect="dark"
|
||||||
>
|
:content="generateIconCode(item)"
|
||||||
<el-tooltip
|
placement="top"
|
||||||
effect="dark"
|
>
|
||||||
:content="generateIconCode(item)"
|
<div class="icon-item">
|
||||||
placement="top"
|
<svg-icon :icon-class="item" />
|
||||||
>
|
<span>{{ item }}</span>
|
||||||
<div class="icon-item">
|
</div>
|
||||||
<svg-icon :icon-class="item" />
|
</el-tooltip>
|
||||||
<span>{{ item }}</span>
|
</copy-button>
|
||||||
</div>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="Element-UI Icons">
|
<el-tab-pane label="Element-UI Icons">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div
|
<div v-for="(icon, name) of icons" :key="name">
|
||||||
v-for="(icon, name) of icons"
|
<copy-button :text="generateElementIconCode(name)">
|
||||||
:key="name"
|
<el-tooltip
|
||||||
@click="handleClipboard(generateElementIconCode(name), $event)"
|
effect="dark"
|
||||||
>
|
:content="generateElementIconCode(name)"
|
||||||
<el-tooltip
|
placement="top"
|
||||||
effect="dark"
|
>
|
||||||
:content="generateElementIconCode(name)"
|
<div class="icon-item">
|
||||||
placement="top"
|
<el-icon :size="20">
|
||||||
>
|
<component :is="icon" />
|
||||||
<div class="icon-item">
|
</el-icon>
|
||||||
<el-icon :size="20">
|
<span>{{ name }}</span>
|
||||||
<component :is="icon" />
|
</div>
|
||||||
</el-icon>
|
</el-tooltip>
|
||||||
<span>{{ name }}</span>
|
</copy-button>
|
||||||
</div>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -99,8 +95,6 @@ const svg_icons: string[] = [
|
|||||||
];
|
];
|
||||||
const icons = ref(ElementPlusIconsVue);
|
const icons = ref(ElementPlusIconsVue);
|
||||||
|
|
||||||
const { copy } = useClipboard();
|
|
||||||
|
|
||||||
function generateIconCode(symbol: any) {
|
function generateIconCode(symbol: any) {
|
||||||
return `<svg-icon icon-class="${symbol}" />`;
|
return `<svg-icon icon-class="${symbol}" />`;
|
||||||
}
|
}
|
||||||
@@ -108,17 +102,6 @@ function generateIconCode(symbol: any) {
|
|||||||
function generateElementIconCode(symbol: any) {
|
function generateElementIconCode(symbol: any) {
|
||||||
return `<el-icon><${symbol} /></el-icon>`;
|
return `<el-icon><${symbol} /></el-icon>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClipboard(text: any, event: any) {
|
|
||||||
// clipboard(text, event);
|
|
||||||
copy(text)
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success("Copy successfully");
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
ElMessage.warning("Copy failed");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user