Merge branch 'main' of github.com:pure-admin/vue-pure-admin into gitee

This commit is contained in:
xiaoxian521 2023-05-24 12:58:59 +08:00
commit 6294a3ffac
28 changed files with 3032 additions and 6149 deletions

View File

@ -1,6 +1,6 @@
# 预发布也需要生产环境的行为
# https://cn.vitejs.dev/guide/env-and-mode.html#modes
NODE_ENV=production
# NODE_ENV = development
VITE_PUBLIC_PATH = /

View File

@ -1,19 +1,19 @@
{
"Vue3.0快速生成模板": {
"scope": "vue",
"prefix": "Vue3.0",
"body": [
"<template>",
"\t<div>\n",
"\t</div>",
"\t<div>test</div>",
"</template>\n",
"<script lang='ts'>",
"export default {",
"\tsetup(){",
"\t\treturn{\n\n\t\t}",
"\t},",
"\tsetup() {",
"\t\treturn {}",
"\t}",
"}",
"</script>\n",
"<style scoped>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],

View File

@ -1,14 +1,14 @@
{
"Vue3.2+快速生成模板": {
"scope": "vue",
"prefix": "Vue3.2+",
"body": [
"<script setup lang='ts'>",
"</script>\n",
"<template>",
"\t<div>\n",
"\t</div>",
"\t<div>test</div>",
"</template>\n",
"<style scoped>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],

20
.vscode/vue3.3.code-snippets vendored Normal file
View File

@ -0,0 +1,20 @@
{
"Vue3.3+defineOptions快速生成模板": {
"scope": "vue",
"prefix": "Vue3.3+",
"body": [
"<script setup lang='ts'>",
"defineOptions({",
"\tname: ''",
"})",
"</script>\n",
"<template>",
"\t<div>test</div>",
"</template>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.3+defineOptions快速生成模板"
}
}

View File

@ -22,7 +22,7 @@ The simplified version is based on the shelf extracted from [vue-pure-admin](htt
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs (support `PWA` fast, offline access)
## Docs
- [Click me to view the domestic documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
- [Click me to view foreign document site](https://pure-admin.github.io/pure-admin-doc)
@ -140,34 +140,12 @@ Support modern browsers, not IE
[xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
## Donate
If you think this project is helpful to you, you can help the author buy a glass of juice 🍹 Show your support
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f69bf13c5b854ed5b699807cafa0e3ce~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?" width="150px" height="150px" />
## License
In principle, no fees and copyrights are charged, and you can use it with confidence, but if you need secondary open source, please contact the author for permission!
In principle, no fees and copyrights are charged, and it is commercially available, but if you need secondary open source (such as using this platform for secondary development and open source, the front-end code must be open source and free), please contact the author for permission! (Free, just take a record)
[MIT © 2020-present, pure-admin](./LICENSE)
## Backers
Thank you very much for your support, I believe the project will get better and better :heart:
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen | BenLakes |
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/BenLakes"><img src="https://avatars.githubusercontent.com/u/15206046?v=4" width="60px" height="60px" /></a> |
| mollerzhu | TLovers | cnyyk | | | |
| <a href="https://github.com/mollerzhu"><img src="https://avatars.githubusercontent.com/u/49627902?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/TLovers"><img src="https://avatars.githubusercontent.com/u/26561694?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/cnyyk"><img src="https://avatars.githubusercontent.com/u/275233?v=4" width="60px" height="60px" /></a> | | | |
## Contributors
Thanks to all the people who contribute :heart:
<a href="https://github.com/pure-admin/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=pure-admin/vue-pure-admin" /></a>
## `Star`
Many thanks to the kind individuals who leave a star. Your support is much appreciated :heart:

View File

@ -22,7 +22,7 @@
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套保姆级文档(支持 `PWA` 快速、离线访问)
## 配套保姆级文档
- [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站](https://pure-admin.github.io/pure-admin-doc)
@ -140,38 +140,12 @@ pnpm build
[xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
## 支持
如果您觉得这个项目对您有帮助,可以帮作者买一杯果汁 🍹 表示支持
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f69bf13c5b854ed5b699807cafa0e3ce~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?" width="150px" height="150px" />
## `QQ` 交流群
[点击去加入](https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4)
## 许可证
原则上不收取任何费用及版权,可以放心使用,不过如需二次开源(比如用此平台二次开发并开源)请联系作者获取许可!
原则上不收取任何费用及版权,可商用,不过如需二次开源(比如用此平台二次开发并开源,要求前端代码必须开源免费)请联系作者获取许可!(免费,走个记录而已)
[MIT © 2020-present, pure-admin](./LICENSE)
## 支持者
非常感谢您们的支持,相信项目会越来越好 :heart:
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen | BenLakes |
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/BenLakes"><img src="https://avatars.githubusercontent.com/u/15206046?v=4" width="60px" height="60px" /></a> |
| mollerzhu | TLovers | cnyyk | | | |
| <a href="https://github.com/mollerzhu"><img src="https://avatars.githubusercontent.com/u/49627902?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/TLovers"><img src="https://avatars.githubusercontent.com/u/26561694?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/cnyyk"><img src="https://avatars.githubusercontent.com/u/275233?v=4" width="60px" height="60px" /></a> | | | |
## 贡献者
感谢所有做出贡献的人 :heart:
<a href="https://github.com/pure-admin/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=pure-admin/vue-pure-admin" /></a>
## `Star`
非常感谢留下星星的好心人,感谢您的支持 :heart:

View File

@ -56,7 +56,7 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^2.1.1",
"pinia": "^2.1.3",
"qrcode": "^1.5.3",
"qs": "^6.11.1",
"responsive-storage": "^2.2.0",
@ -69,7 +69,7 @@
"vue-i18n": "^9.2.2",
"vue-json-pretty": "^2.2.4",
"vue-pdf-embed": "^1.1.6",
"vue-router": "^4.2.0",
"vue-router": "^4.2.1",
"vue-types": "^5.0.3",
"vue-virtual-scroller": "2.0.0-beta.7",
"vue-waterfall-plugin-next": "^2.2.1",
@ -104,9 +104,9 @@
"autoprefixer": "^10.4.14",
"cloc": "^2.11.0",
"cssnano": "^6.0.1",
"eslint": "^8.40.0",
"eslint": "^8.41.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.13.0",
"eslint-plugin-vue": "^9.14.0",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"picocolors": "^1.0.0",
@ -114,12 +114,12 @@
"postcss-html": "^1.5.0",
"postcss-import": "^15.1.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.7",
"pretty-quick": "3.1.1",
"rimraf": "^5.0.0",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3",
"rimraf": "^5.0.1",
"rollup-plugin-visualizer": "^5.9.0",
"sass": "^1.62.1",
"sass-loader": "^13.2.2",
"sass-loader": "^13.3.0",
"stylelint": "^15.6.2",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.0.0",
@ -133,9 +133,9 @@
"stylelint-scss": "^5.0.0",
"svgo": "^3.0.2",
"tailwindcss": "^3.3.2",
"terser": "^5.17.4",
"terser": "^5.17.5",
"typescript": "^5.0.4",
"vite": "^4.3.7",
"vite": "^4.3.8",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6",

8592
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -12,6 +12,7 @@ import type {
const dialogStore = ref<Array<DialogOptions>>([]);
/** 打开弹框 */
const addDialog = (options: DialogOptions) => {
const open = () =>
dialogStore.value.push(Object.assign(options, { visible: true }));
@ -24,16 +25,40 @@ const addDialog = (options: DialogOptions) => {
}
};
/** 关闭弹框 */
const closeDialog = (options: DialogOptions, index: number, args?: any) => {
dialogStore.value.splice(index, 1);
options.closeCallBack && options.closeCallBack({ options, index, args });
};
/**
* @description
* @param value
* @param key `title`
* @param index `0``index`
*/
const updateDialog = (value: any, key = "title", index = 0) => {
dialogStore.value[index][key] = value;
};
/** 关闭所有弹框 */
const closeAllDialog = () => {
dialogStore.value = [];
};
/** 使`addDialog`
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L4
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L13
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L18
*/
const ReDialog = withInstall(reDialog);
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
export { ReDialog, dialogStore, addDialog, closeDialog, closeAllDialog };
export {
ReDialog,
dialogStore,
addDialog,
closeDialog,
updateDialog,
closeAllDialog
};

View File

@ -200,9 +200,13 @@ export default defineComponent({
return () => (
<>
<div {...attrs} class="w-[99/100] mt-4 px-2 pb-2 bg-bg_color">
<div {...attrs} class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
<div class="flex justify-between w-full h-[60px] p-4">
<p class="font-bold truncate">{props.title}</p>
{slots?.title ? (
slots.title()
) : (
<p class="font-bold truncate">{props.title}</p>
)}
<div class="flex items-center justify-around">
{slots?.buttons ? (
<div class="flex mr-4">{slots.buttons()}</div>

View File

@ -51,20 +51,21 @@ let startPosX = null;
let isHover = false;
let ease = "ease-in";
// eslint-disable-next-line vue/no-setup-props-destructure
const { classOption } = props;
if (classOption["key"] === undefined) {
classOption["key"] = 0;
if (props.classOption["key"] === undefined) {
// eslint-disable-next-line vue/no-mutating-props
props.classOption["key"] = 0;
}
const wrap = templateRef<HTMLElement | null>(`wrap${classOption["key"]}`, null);
const wrap = templateRef<HTMLElement | null>(
`wrap${props.classOption["key"]}`,
null
);
const slotList = templateRef<HTMLElement | null>(
`slotList${classOption["key"]}`,
`slotList${props.classOption["key"]}`,
null
);
const realBox = templateRef<HTMLElement | null>(
`realBox${classOption["key"]}`,
`realBox${props.classOption["key"]}`,
null
);
@ -107,7 +108,7 @@ const defaultOption = computed(() => {
const options = computed(() => {
// @ts-expect-error
return copyObj({}, unref(defaultOption), classOption);
return copyObj({}, unref(defaultOption), props.classOption);
});
const leftSwitchClass = computed(() => {
@ -495,7 +496,7 @@ defineExpose({
</script>
<template>
<div :ref="'wrap' + classOption['key']">
<div :ref="'wrap' + props.classOption['key']">
<div
:style="leftSwitch"
v-if="navigation"
@ -513,7 +514,7 @@ defineExpose({
<slot name="right-switch" />
</div>
<div
:ref="'realBox' + classOption['key']"
:ref="'realBox' + props.classOption['key']"
:style="pos"
@mouseenter="enter"
@mouseleave="leave"
@ -522,7 +523,7 @@ defineExpose({
@touchend="touchEnd"
@mousewheel.passive="wheel"
>
<div :ref="'slotList' + classOption['key']" :style="float">
<div :ref="'slotList' + props.classOption['key']" :style="float">
<slot />
</div>
<div v-html="copyHtml" :style="float" />

View File

@ -164,7 +164,7 @@ onKeyStroke("ArrowDown", handleDown);
</template>
</el-input>
<div class="search-result-container">
<el-scrollbar ref="scrollbarRef" max-height="600px">
<el-scrollbar ref="scrollbarRef" max-height="calc(90vh - 140px)">
<el-empty
v-if="resultOptions.length === 0"
description="暂无搜索结果"

View File

@ -1,8 +1,9 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { computed, getCurrentInstance } from "vue";
import { useResizeObserver } from "@vueuse/core";
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, computed, getCurrentInstance, onMounted } from "vue";
import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
import Bookmark2Line from "@iconify-icons/ri/bookmark-2-line";
@ -26,6 +27,8 @@ interface Emits {
(e: "enter"): void;
}
const resultRef = ref();
const innerHeight = ref();
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<Emits>();
const instance = getCurrentInstance()!;
@ -59,19 +62,32 @@ function handleTo() {
emit("enter");
}
function resizeResult() {
// el-scrollbar max-height="calc(90vh - 140px)"
innerHeight.value = window.innerHeight - window.innerHeight / 10 - 140;
}
useResizeObserver(resultRef, () => {
resizeResult();
});
function handleScroll(index: number) {
const curInstance = instance?.proxy?.$refs[`resultItemRef${index}`];
if (!curInstance) return 0;
const curRef = curInstance[0] as ElRef;
const scrollTop = curRef.offsetTop + 128; // 128 result-item56px+56px=112pxmargin8px+8px=16px
return scrollTop > 600 ? scrollTop - 600 : 0; // 600 el-scrollbar max-height="600px"
return scrollTop > innerHeight.value ? scrollTop - innerHeight.value : 0;
}
onMounted(() => {
resizeResult();
});
defineExpose({ handleScroll });
</script>
<template>
<div class="result">
<div ref="resultRef" class="result">
<div
v-for="(item, index) in options"
:key="item.path"

View File

@ -218,7 +218,6 @@ watch($storage, ({ layout }) => {
});
onBeforeMount(() => {
dataThemeChange();
/* 初始化项目配置 */
nextTick(() => {
settings.greyVal &&

View File

@ -8,7 +8,15 @@ import { useLayout } from "./hooks/useLayout";
import { useAppStoreHook } from "@/store/modules/app";
import { useSettingStoreHook } from "@/store/modules/settings";
import { deviceDetection, useDark, useGlobal } from "@pureadmin/utils";
import { h, reactive, computed, onMounted, defineComponent } from "vue";
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import {
h,
reactive,
computed,
onMounted,
onBeforeMount,
defineComponent
} from "vue";
import navbar from "./components/navbar.vue";
import tag from "./components/tag/index.vue";
@ -102,6 +110,10 @@ onMounted(() => {
}
});
onBeforeMount(() => {
useDataThemeChange().dataThemeChange();
});
const layoutHeader = defineComponent({
render() {
return h(

View File

@ -23,7 +23,7 @@ import {
formatFlatteningRoutes
} from "./utils";
import { buildHierarchyTree } from "@/utils/tree";
import { isUrl, openLink, storageSession } from "@pureadmin/utils";
import { isUrl, openLink, storageSession, isAllEmpty } from "@pureadmin/utils";
import remainingRouter from "./modules/remaining";
@ -158,11 +158,22 @@ router.beforeEach((to: toRouteType, _from, next) => {
getTopMenu(true);
// query、params模式路由传参数的标签页不在此处处理
if (route && route.meta?.title) {
useMultiTagsStoreHook().handleTags("push", {
path: route.path,
name: route.name,
meta: route.meta
});
if (isAllEmpty(route.parentId) && route.meta?.backstage) {
// 此处为动态顶级路由(目录)
const { path, name, meta } = route.children[0];
useMultiTagsStoreHook().handleTags("push", {
path,
name,
meta
});
} else {
const { path, name, meta } = route;
useMultiTagsStoreHook().handleTags("push", {
path,
name,
meta
});
}
}
}
router.push(to.fullPath);

View File

@ -3,7 +3,7 @@ import { components } from "@/router/enums";
export default {
path: "/components",
redirect: "/components/video",
redirect: "/components/dialog",
meta: {
icon: "menu",
title: $t("menus.hscomponents"),

View File

@ -54,14 +54,14 @@ export function useColumns() {
}
},
{
label: "QQ交流群",
label: "精简版",
cellRenderer: () => {
return (
<a
href="https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4"
href="https://github.com/pure-admin/pure-admin-thin"
target="_blank"
>
<span style="color: var(--el-color-primary)"></span>
<span style="color: var(--el-color-primary)"></span>
</a>
);
}

View File

@ -2,9 +2,14 @@
import { useRouter } from "vue-router";
import { h, createVNode, ref } from "vue";
import { message } from "@/utils/message";
import { cloneDeep } from "@pureadmin/utils";
import forms, { type FormProps } from "./form.vue";
import { addDialog, closeDialog, closeAllDialog } from "@/components/ReDialog";
import { cloneDeep, debounce } from "@pureadmin/utils";
import {
addDialog,
closeDialog,
updateDialog,
closeAllDialog
} from "@/components/ReDialog";
defineOptions({
name: "DialogPage"
@ -60,13 +65,16 @@ function onStyleClick() {
});
}
function onoOpenDelayClick() {
addDialog({
title: "延时2秒打开弹框",
openDelay: 2000,
contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
});
}
// 600ms
const onoOpenDelayClick = debounce(
() =>
addDialog({
title: "延时2秒打开弹框",
openDelay: 2000 - 600,
contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
}),
600
);
function onCloseDelayClick() {
addDialog({
@ -240,6 +248,35 @@ function onNestingClick() {
});
}
// contentRenderer
function onUpdateClick() {
const curPage = ref(1);
addDialog({
title: `${curPage.value}`,
contentRenderer: () => (
<>
<el-button
disabled={curPage.value > 1 ? false : true}
onClick={() => {
curPage.value -= 1;
updateDialog(`${curPage.value}`);
}}
>
上一页
</el-button>
<el-button
onClick={() => {
curPage.value += 1;
updateDialog(`${curPage.value}`);
}}
>
下一页
</el-button>
</>
)
});
}
// Form props prop
function onFormOneClick() {
addDialog({
@ -421,6 +458,7 @@ function onBeforeSureClick() {
<el-button @click="onOpenClick"> 打开后的回调 </el-button>
<el-button @click="onCloseCallBackClick"> 关闭后的回调 </el-button>
<el-button @click="onNestingClick"> 嵌套的弹框 </el-button>
<el-button @click="onUpdateClick"> 更改弹框自身属性值 </el-button>
</el-space>
<el-divider />
<el-space wrap>

View File

@ -0,0 +1,56 @@
<script setup lang="ts">
import "@wangeditor/editor/dist/css/style.css";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
defineOptions({
name: "BaseEditor"
});
const mode = "default";
// shallowRef
const editorRef = shallowRef();
// HTML
const valueHtml = ref("<p>你好</p>");
// ajax
onMounted(() => {
setTimeout(() => {
valueHtml.value = "<p>我是模拟的异步数据</p>";
}, 1500);
});
const toolbarConfig: any = { excludeKeys: "fullScreen" };
const editorConfig = { placeholder: "请输入内容..." };
const handleCreated = editor => {
// editor
editorRef.value = editor;
};
//
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
</script>
<template>
<div class="wangeditor">
<Toolbar
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
style="border-bottom: 1px solid #ccc"
/>
<Editor
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
style="height: 500px; overflow-y: hidden"
@onCreated="handleCreated"
/>
</div>
</template>

View File

@ -0,0 +1,9 @@
import base from "./base.vue";
import multi from "./multi.vue";
import picUpload from "./picUpload.vue";
const Base = base;
const Multi = multi;
const PicUpload = picUpload;
export { Base, Multi, PicUpload };

View File

@ -0,0 +1,76 @@
<script setup lang="ts">
import ReCol from "@/components/ReCol";
import { onBeforeUnmount, ref, shallowRef } from "vue";
import "@wangeditor/editor/dist/css/style.css";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
defineOptions({
name: "MultiEditor"
});
//
const endEditorList = [
{
value: "<p>测试一</p>"
},
{
value: "<p>测试二</p>"
},
{
value: "<p>测试三</p>"
},
{
value: "<p>测试四</p>"
}
];
// Toolbar editor shallowRef
const editorList = ref([]);
endEditorList.forEach(edit => {
editorList.value.push({
value: edit.value,
// shallowRef
editorRef: shallowRef()
});
});
const mode = "default";
const toolbarConfig: any = { excludeKeys: "fullScreen" };
const editorConfig = { placeholder: "请输入内容..." };
const handleCreated = (editor, index) => {
// editor
editorList.value[index].editorRef = editor;
};
//
onBeforeUnmount(() => {
return editorList.value.map(edit => {
if (edit.editorRef == null) return;
edit.editorRef.destroy();
});
});
</script>
<template>
<el-row :gutter="30" justify="space-around">
<re-col :value="11" v-for="(edit, index) in editorList" :key="index">
<div class="wangeditor">
<Toolbar
:editor="edit.editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
style="border-bottom: 1px solid #ccc"
/>
<Editor
v-model="edit.value"
:defaultConfig="editorConfig"
:mode="mode"
style="height: 300px; overflow-y: hidden"
@onCreated="editor => handleCreated(editor, index)"
/>
</div>
</re-col>
</el-row>
</template>

View File

@ -0,0 +1,70 @@
<script setup lang="ts">
import { onBeforeUnmount, ref, shallowRef } from "vue";
import "@wangeditor/editor/dist/css/style.css";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
defineOptions({
name: "picUpload"
});
const mode = "default";
// shallowRef
const editorRef = shallowRef();
// HTML
const valueHtml = ref(
"<p>仅提供代码参考,暂不可上传图片,可根据实际业务改写</p>"
);
const toolbarConfig: any = { excludeKeys: "fullScreen" };
const editorConfig = { placeholder: "请输入内容...", MENU_CONF: {} };
// https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87
editorConfig.MENU_CONF["uploadImage"] = {
//
server: "",
// form-data fieldName
fieldName: "file",
//
allowedFileTypes: ["image/png", "image/jpg", "image/jpeg"],
//
customInsert(res: any, insertFn) {
// res.data.url
if (res.data.url) {
setTimeout(() => {
// insertFn
insertFn(res.data.url);
}, 2000);
}
}
};
const handleCreated = editor => {
// editor
editorRef.value = editor;
};
//
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
</script>
<template>
<div class="wangeditor">
<Toolbar
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
style="border-bottom: 1px solid #ccc"
/>
<Editor
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
style="height: 500px; overflow-y: hidden"
@onCreated="handleCreated"
/>
</div>
</template>

View File

@ -1,41 +1,12 @@
<script setup lang="ts">
import "@wangeditor/editor/dist/css/style.css"; // css
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
import Edit from "@iconify-icons/ep/edit";
import { ref } from "vue";
import { Base, Multi, PicUpload } from "./components";
defineOptions({
name: "Editor"
});
const mode = "default";
// shallowRef
const editorRef = shallowRef();
// HTML
const valueHtml = ref("<p>hello</p>");
// ajax
onMounted(() => {
setTimeout(() => {
valueHtml.value = "<p>模拟 Ajax 异步设置内容</p>";
}, 1500);
});
const toolbarConfig: any = { excludeKeys: "fullScreen" };
const editorConfig = { placeholder: "请输入内容..." };
//
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
const handleCreated = editor => {
editorRef.value = editor; // editor
};
const activeNames = ref(["1"]);
</script>
<template>
@ -47,7 +18,6 @@ const handleCreated = editor => {
<el-link
href="https://www.wangeditor.com"
target="_blank"
:icon="useRenderIcon(Edit)"
style="margin: 0 4px 5px; font-size: 16px"
>
Wangeditor
@ -55,20 +25,22 @@ const handleCreated = editor => {
</span>
</div>
</template>
<div class="wangeditor">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
</div>
<el-collapse v-model="activeNames" accordion>
<el-collapse-item title="基础用法" name="1">
<Base />
</el-collapse-item>
<el-collapse-item title="多个富文本" name="2">
<Multi />
</el-collapse-item>
<el-collapse-item title="自定义图片上传" name="3">
<PicUpload />
</el-collapse-item>
</el-collapse>
</el-card>
</template>
<style lang="scss" scoped>
:deep(.el-collapse-item__header) {
padding-left: 10px;
}
</style>