From 240a0bd779b768d2b4a83e2f96d9f9bdb74e12fd Mon Sep 17 00:00:00 2001 From: bqy_fe <1743369777@qq.com> Date: Mon, 14 Jun 2021 18:50:33 +0800 Subject: [PATCH] perf: dragable components --- README.EN.md | 7 +- README.md | 7 +- package.json | 6 +- preview/views/comp-render.tsx | 15 +++- src/hooks/useAnimate.ts | 39 +++++++--- src/packages/base-widgets/divider/index.tsx | 13 +++- src/packages/base-widgets/image/index.tsx | 6 +- src/packages/base-widgets/input/index.tsx | 6 ++ .../notice-bar/createFieldProps.ts | 44 ++++++++++++ .../base-widgets/notice-bar/index.tsx | 37 ++++++++++ src/packages/base-widgets/picker/index.tsx | 2 +- src/packages/base-widgets/process/index.tsx | 6 +- src/packages/base-widgets/rate/index.tsx | 2 +- src/packages/base-widgets/stepper/index.tsx | 2 +- .../base-widgets/swipe/createFieldProps.ts | 33 +++++++++ src/packages/base-widgets/swipe/index.tsx | 54 ++++++++++++++ src/packages/base-widgets/text/fontArr.ts | 54 ++++++++++++++ src/packages/base-widgets/text/index.tsx | 10 +-- .../components/common/simulator.vue | 2 +- .../components/header/useTools.tsx | 2 +- .../components/animate/Animate.tsx | 9 +-- .../components/attr-editor/AttrEditor.tsx | 39 ++++++---- .../cross-sortable-options.tsx | 72 +++++++++++++++++++ .../right-attribute-panel/components/index.ts | 15 ++-- .../components/page-setting/pageSetting.tsx | 8 +++ .../right-attribute-panel/index.common.scss | 17 ----- .../right-attribute-panel/index.module.scss | 10 +++ .../right-attribute-panel/index.tsx | 6 +- .../simulator-editor/comp-render.tsx | 12 +++- .../draggable-transition-group.vue | 6 +- .../simulator-editor/simulator-editor.vue | 14 +++- .../components/simulator-editor/slot-item.vue | 2 +- src/visual-editor/hooks/useVisualData.ts | 2 + src/visual-editor/visual-editor.props.tsx | 27 ++++++- yarn.lock | 36 +++++----- 35 files changed, 513 insertions(+), 109 deletions(-) create mode 100644 src/packages/base-widgets/notice-bar/createFieldProps.ts create mode 100644 src/packages/base-widgets/notice-bar/index.tsx create mode 100644 src/packages/base-widgets/swipe/createFieldProps.ts create mode 100644 src/packages/base-widgets/swipe/index.tsx create mode 100644 src/packages/base-widgets/text/fontArr.ts create mode 100644 src/visual-editor/components/right-attribute-panel/components/cross-sortable-options/cross-sortable-options.tsx create mode 100644 src/visual-editor/components/right-attribute-panel/components/page-setting/pageSetting.tsx delete mode 100644 src/visual-editor/components/right-attribute-panel/index.common.scss diff --git a/README.EN.md b/README.EN.md index aefc5d1..d4b9649 100644 --- a/README.EN.md +++ b/README.EN.md @@ -52,8 +52,13 @@ let propObj = { $$('#props + table tr').reduce((prev, curr) => { const children = curr.children const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase()) + const child3Text = children[3].textContent + const defaultValue = ['true', 'false'].includes(child3Text) + ? child3Text + : `'${child3Text == '-' ? '' : child3Text}'` const value = (propObj[children[2].textContent] ?? propObj['string'])({ - label: `'${children[1].textContent}'` + label: `'${children[1].textContent}'`, + defaultValue }).replaceAll('"', '') prev[key] = value return prev diff --git a/README.md b/README.md index 1d1d01c..2e1ecdd 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,13 @@ let propObj = { $$('#props + table tr').reduce((prev, curr) => { const children = curr.children const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase()) + const child3Text = children[3].textContent + const defaultValue = ['true', 'false'].includes(child3Text) + ? child3Text + : `'${child3Text == '-' ? '' : child3Text}'` const value = (propObj[children[2].textContent] ?? propObj['string'])({ - label: `'${children[1].textContent}'` + label: `'${children[1].textContent}'`, + defaultValue }).replaceAll('"', '') prev[key] = value return prev diff --git a/package.json b/package.json index 49adfc1..a3e4a89 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ }, "dependencies": { "@vant/touch-emulator": "^1.3.0", - "@vueuse/core": "^5.0.2", - "@vueuse/integrations": "^5.0.2", + "@vueuse/core": "^5.0.3", + "@vueuse/integrations": "^5.0.3", "animate.css": "^4.1.1", "axios": "^0.21.1", "dayjs": "^1.10.5", @@ -56,7 +56,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.23.4", "eslint-plugin-prettier": "^3.4.0", - "eslint-plugin-vue": "^7.11.0", + "eslint-plugin-vue": "^7.11.1", "gh-pages": "^3.2.0", "husky": "^6.0.0", "lint-staged": "^11.0.0", diff --git a/preview/views/comp-render.tsx b/preview/views/comp-render.tsx index 289b7d2..5783fb0 100644 --- a/preview/views/comp-render.tsx +++ b/preview/views/comp-render.tsx @@ -1,14 +1,23 @@ -import { defineComponent } from 'vue' +/* + * @Author: 卜启缘 + * @Date: 2021-05-04 05:36:58 + * @LastEditTime: 2021-06-14 10:03:06 + * @LastEditors: 卜启缘 + * @Description: + * @FilePath: \vite-vue3-lowcode\preview\views\comp-render.tsx + */ +import { defineComponent, PropType } from 'vue' +import { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils' export default defineComponent({ name: 'CompRender', props: { element: { - type: Object, + type: Object as PropType, default: () => ({}) }, config: { - type: Object, + type: Object as PropType, default: () => ({}) } }, diff --git a/src/hooks/useAnimate.ts b/src/hooks/useAnimate.ts index 1c9352d..ae683c4 100644 --- a/src/hooks/useAnimate.ts +++ b/src/hooks/useAnimate.ts @@ -1,7 +1,7 @@ /* * @Author: 卜启缘 * @Date: 2021-06-12 21:29:32 - * @LastEditTime: 2021-06-12 22:03:43 + * @LastEditTime: 2021-06-13 19:27:04 * @LastEditors: 卜启缘 * @Description: 执行组件动画 * @FilePath: \vite-vue3-lowcode\src\hooks\useAnimate.ts @@ -9,30 +9,47 @@ import { Animation } from '@/visual-editor/visual-editor.utils' -export const useAnimate = async (animateEl: HTMLElement, animations: Animation | Animation[]) => { +export const useAnimate = async ( + animateEl: HTMLElement, + animations: Animation | Animation[], + prefixCls = 'animate__' +) => { animations = Array.isArray(animations) ? animations : [animations] const play = (animate: Animation) => new Promise((resolve) => { if (animateEl) { - const animationName = `animate__${animate.value}` - animateEl.style.setProperty('--animate-duration', `${animate.duration}s`) - animateEl.style.setProperty('--animate-delay', `${animate.delay}s`) - animateEl.style.setProperty( - 'animation-iteration-count', - `${animate.infinite ? 'infinite' : animate.count}` - ) + const animationName = `${prefixCls}${animate.value}` + + // 过滤可能残留的animate.css动画类名 + animateEl.classList.value = animateEl.classList.value + .split(' ') + .filter((item) => !item.includes(prefixCls)) + .join(' ') + + // 设置动画属性 + const setAnimate = () => { + animateEl.style.setProperty('--animate-duration', `${animate.duration}s`) + animateEl.style.setProperty('animation-delay', `${animate.delay}s`) + animateEl.style.setProperty( + 'animation-iteration-count', + `${animate.infinite ? 'infinite' : animate.count}` + ) + animateEl?.classList.add(`${prefixCls}animated`, animationName) + } // 动画结束时,删除类名 const handleAnimationEnd = (event?: AnimationEvent) => { event?.stopPropagation() - animateEl.classList.remove(`animate__animated`, animationName) + animateEl.classList.remove(`${prefixCls}animated`, animationName) animateEl.removeEventListener('animationend', handleAnimationEnd) resolve('animation end') } - animateEl?.classList.add(`animate__animated`, animationName) + setAnimate() + animateEl?.addEventListener('animationend', handleAnimationEnd, { once: true }) + // animateEl?.addEventListener('animationcancel', handleAnimationEnd, { once: true }) } else { resolve('动画执行失败!执行动画元素不存在!') } diff --git a/src/packages/base-widgets/divider/index.tsx b/src/packages/base-widgets/divider/index.tsx index d4ffedb..e4fcad5 100644 --- a/src/packages/base-widgets/divider/index.tsx +++ b/src/packages/base-widgets/divider/index.tsx @@ -6,16 +6,23 @@ import { createEditorSelectProp } from '@/visual-editor/visual-editor.props' import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' +import { useGlobalProperties } from '@/hooks/useGlobalProperties' export default { key: 'divider', moduleName: 'baseWidgets', label: '分割线', preview: () => 文本, - render: ({ props }) => { - const style = `color:${props['text-color']};borderColor:${props['divider-color']}` + render: ({ props, block }) => { + const { registerRef } = useGlobalProperties() + + const style = { + color: props['text-color'], + borderColor: props['divider-color'] + } + return ( - + registerRef(el, block._vid)} {...props} style={style}> {{ default: () => props.text }} diff --git a/src/packages/base-widgets/image/index.tsx b/src/packages/base-widgets/image/index.tsx index 69f3f60..d5d6de4 100644 --- a/src/packages/base-widgets/image/index.tsx +++ b/src/packages/base-widgets/image/index.tsx @@ -1,7 +1,7 @@ /* * @Author: 卜启缘 * @Date: 2021-06-01 09:45:21 - * @LastEditTime: 2021-06-12 09:55:10 + * @LastEditTime: 2021-06-14 10:31:27 * @LastEditors: 卜启缘 * @Description: 图片组件 * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx @@ -32,8 +32,8 @@ export default { ), render: ({ props, block }) => { const { registerRef } = useGlobalProperties() - const ImageComp = () => registerRef(el, block._vid)} {...props} /> - return + + return registerRef(el, block._vid)} {...props} /> }, props: { src: createEditorInputProp({ diff --git a/src/packages/base-widgets/input/index.tsx b/src/packages/base-widgets/input/index.tsx index 1b2cb18..0f96cfb 100644 --- a/src/packages/base-widgets/input/index.tsx +++ b/src/packages/base-widgets/input/index.tsx @@ -13,6 +13,11 @@ export default { render: ({ model, size, block, props, custom }) => { const { registerRef } = useGlobalProperties() + let rules = [] + try { + rules = JSON.parse(props.rules) + } catch (e) {} + return ( registerRef(el, block._vid)} @@ -20,6 +25,7 @@ export default { {...props} {...model.default} v-model={props.modelValue} + rules={rules} style={{ width: size.width ? `${size.width}px` : null }} diff --git a/src/packages/base-widgets/notice-bar/createFieldProps.ts b/src/packages/base-widgets/notice-bar/createFieldProps.ts new file mode 100644 index 0000000..d9576cd --- /dev/null +++ b/src/packages/base-widgets/notice-bar/createFieldProps.ts @@ -0,0 +1,44 @@ +/* + * @Author: 卜启缘 + * @Date: 2021-06-14 12:24:12 + * @LastEditTime: 2021-06-14 12:38:02 + * @LastEditors: 卜启缘 + * @Description: + * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\createFieldProps.ts + */ +import { + createEditorInputProp, + createEditorSelectProp, + createEditorSwitchProp +} from '@/visual-editor/visual-editor.props' + +export const createFieldProps = () => ({ + background: createEditorInputProp({ label: '滚动条背景' }), + color: createEditorInputProp({ label: '通知文本颜色' }), + delay: createEditorInputProp({ label: '动画延迟时间 (s)' }), + leftIcon: createEditorInputProp({ label: '左侧图标名称或图片链接', defaultValue: 'volume-o' }), + mode: createEditorSelectProp({ + label: '通知栏模式', + options: [ + { + label: '默认', + value: '' + }, + { + label: '可关闭', + value: 'closeable' + }, + { + label: '链接', + value: 'link' + } + ] + }), + scrollable: createEditorSwitchProp({ label: '是否开启滚动播放,内容长度溢出时默认开启' }), + speed: createEditorInputProp({ label: '滚动速率 (px/s)' }), + text: createEditorInputProp({ + label: '通知文本内容', + defaultValue: '在代码阅读过程中人们说脏话的频率是衡量代码质量的唯一标准。' + }), + wrapable: createEditorSwitchProp({ label: '是否开启文本换行,只在禁用滚动时生效' }) +}) diff --git a/src/packages/base-widgets/notice-bar/index.tsx b/src/packages/base-widgets/notice-bar/index.tsx new file mode 100644 index 0000000..9db58ab --- /dev/null +++ b/src/packages/base-widgets/notice-bar/index.tsx @@ -0,0 +1,37 @@ +/* + * @Author: 卜启缘 + * @Date: 2021-06-14 12:24:12 + * @LastEditTime: 2021-06-14 12:56:23 + * @LastEditors: 卜启缘 + * @Description: + * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\index.tsx + */ +import { NoticeBar } from 'vant' +import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' +import { createFieldProps } from './createFieldProps' +import { useGlobalProperties } from '@/hooks/useGlobalProperties' + +export default { + key: 'NoticeBar', + moduleName: 'baseWidgets', + label: '通知栏', + preview: () => ( + + ), + render: ({ block, props }) => { + const { registerRef } = useGlobalProperties() + + return registerRef(el, block._vid)} {...props} /> + }, + props: createFieldProps(), + resize: { + width: true + }, + model: { + default: '绑定字段' + } +} as VisualEditorComponent diff --git a/src/packages/base-widgets/picker/index.tsx b/src/packages/base-widgets/picker/index.tsx index 1589dc3..6be6b39 100644 --- a/src/packages/base-widgets/picker/index.tsx +++ b/src/packages/base-widgets/picker/index.tsx @@ -49,7 +49,7 @@ export default { ) }} - + registerRef(el, block._vid)} {...props} diff --git a/src/packages/base-widgets/process/index.tsx b/src/packages/base-widgets/process/index.tsx index b000fa8..b033beb 100644 --- a/src/packages/base-widgets/process/index.tsx +++ b/src/packages/base-widgets/process/index.tsx @@ -11,9 +11,11 @@ export default { key: 'process', moduleName: 'baseWidgets', label: '进度条', - preview: () => , + preview: () => , render: ({ props }) => { - return + const RenderProgress = () => + + return }, props: { percentage: createEditorInputNumberProp({ label: '进度百分比', defaultValue: 50 }), diff --git a/src/packages/base-widgets/rate/index.tsx b/src/packages/base-widgets/rate/index.tsx index cce8b2f..e70feb5 100644 --- a/src/packages/base-widgets/rate/index.tsx +++ b/src/packages/base-widgets/rate/index.tsx @@ -11,7 +11,7 @@ import { export default { key: 'rate', moduleName: 'baseWidgets', - label: '表单项类型 - 单选框', + label: '表单项类型 - 评分', preview: () => ( ( ({ + images: createEditorCrossSortableProp({ + label: '图片列表', + labelPosition: 'top', + defaultValue: ['https://img.yzcdn.cn/vant/apple-1.jpg', 'https://img.yzcdn.cn/vant/apple-2.jpg'] + }), + width: createEditorInputProp({ label: '滑块宽度,单位为 px', defaultValue: 'auto' }), + height: createEditorInputProp({ label: '滑块高度,单位为 px', defaultValue: '200' }), + autoplay: createEditorInputProp({ label: '自动轮播间隔,单位为 ms', defaultValue: '' }), + duration: createEditorInputProp({ label: '动画时长,单位为 ms', defaultValue: '500' }), + indicatorColor: createEditorInputProp({ label: '指示器颜色', defaultValue: '#1989fa' }), + initialSwipe: createEditorInputProp({ label: '初始位置索引值', defaultValue: '0' }), + lazyRender: createEditorSwitchProp({ label: '是否延迟渲染未展示的轮播', defaultValue: false }), + loop: createEditorSwitchProp({ label: '是否开启循环播放', defaultValue: true }), + showIndicators: createEditorSwitchProp({ label: '是否显示指示器', defaultValue: true }), + stopPropagation: createEditorSwitchProp({ label: '是否阻止滑动事件冒泡', defaultValue: true }), + touchable: createEditorSwitchProp({ label: '是否可以通过手势滑动', defaultValue: true }), + vertical: createEditorSwitchProp({ label: '是否为纵向滚动', defaultValue: false }) +}) diff --git a/src/packages/base-widgets/swipe/index.tsx b/src/packages/base-widgets/swipe/index.tsx new file mode 100644 index 0000000..8d77e25 --- /dev/null +++ b/src/packages/base-widgets/swipe/index.tsx @@ -0,0 +1,54 @@ +/* + * @Author: 卜启缘 + * @Date: 2021-06-14 12:24:12 + * @LastEditTime: 2021-06-14 18:48:44 + * @LastEditors: 卜启缘 + * @Description: + * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\index.tsx + */ +import { Swipe, SwipeItem } from 'vant' +import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' +import { createFieldProps } from './createFieldProps' +import { useGlobalProperties } from '@/hooks/useGlobalProperties' + +const swipeItemStyle = `color: #fff; +font-size: 20px; +line-height: 150px; +text-align: center; +background-color: #39a9ed;` + +export default { + key: 'swipe', + moduleName: 'baseWidgets', + label: '轮播图', + preview: () => ( + + 1 + 2 + 3 + 4 + + ), + render: ({ block, props }) => { + const { registerRef } = useGlobalProperties() + + return ( + registerRef(el, block._vid)} {...props}> + {props.images?.map((item) => ( + <> + + + + + ))} + + ) + }, + props: createFieldProps(), + resize: { + width: true + }, + model: { + default: '绑定字段' + } +} as VisualEditorComponent diff --git a/src/packages/base-widgets/text/fontArr.ts b/src/packages/base-widgets/text/fontArr.ts new file mode 100644 index 0000000..14d3c8b --- /dev/null +++ b/src/packages/base-widgets/text/fontArr.ts @@ -0,0 +1,54 @@ +/* + * @Author: 卜启缘 + * @Date: 2021-06-14 00:53:21 + * @LastEditTime: 2021-06-14 00:55:55 + * @LastEditors: 卜启缘 + * @Description: 可用字体集 + * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\fontArr.ts + */ +export const fontArr = [ + { label: '宋体', value: 'SimSun' }, + { label: '黑体', value: 'SimHei' }, + { label: '微软雅黑', value: 'Microsoft Yahei' }, + { label: '微软正黑体', value: 'Microsoft JhengHei' }, + { label: '楷体', value: 'KaiTi' }, + { label: '新宋体', value: 'NSimSun' }, + { label: '仿宋', value: 'FangSong' }, + { label: '苹方', value: 'PingFang SC' }, + { label: '华文黑体', value: 'STHeiti' }, + { label: '华文楷体', value: 'STKaiti' }, + { label: '华文宋体', value: 'STSong' }, + { label: '华文仿宋', value: 'STFangsong' }, + { label: '华文中宋', value: 'STZhongsong' }, + { label: '华文琥珀', value: 'STHupo' }, + { label: '华文新魏', value: 'STXinwei' }, + { label: '华文隶书', value: 'STLiti' }, + { label: '华文行楷', value: 'STXingkai' }, + { label: '冬青黑体简', value: 'Hiragino Sans GB' }, + { label: '兰亭黑-简', value: 'Lantinghei SC' }, + { label: '翩翩体-简', value: 'Hanzipen SC' }, + { label: '手札体-简', value: 'Hannotate SC' }, + { label: '宋体-简', value: 'Songti SC' }, + { label: '娃娃体-简', value: 'Wawati SC' }, + { label: '魏碑-简', value: 'Weibei SC' }, + { label: '行楷-简', value: 'Xingkai SC' }, + { label: '雅痞-简', value: 'Yapi SC' }, + { label: '圆体-简', value: 'Yuanti SC' }, + { label: '幼圆', value: 'YouYuan' }, + { label: '隶书', value: 'LiSu' }, + { label: '华文细黑', value: 'STXihei' }, + { label: '华文楷体', value: 'STKaiti' }, + { label: '华文宋体', value: 'STSong' }, + { label: '华文仿宋', value: 'STFangsong' }, + { label: '华文中宋', value: 'STZhongsong' }, + { label: '华文彩云', value: 'STCaiyun' }, + { label: '华文琥珀', value: 'STHupo' }, + { label: '华文新魏', value: 'STXinwei' }, + { label: '华文隶书', value: 'STLiti' }, + { label: '华文行楷', value: 'STXingkai' }, + { label: '方正舒体', value: 'FZShuTi' }, + { label: '方正姚体', value: 'FZYaoti' }, + { label: '思源黑体', value: 'Source Han Sans CN' }, + { label: '思源宋体', value: 'Source Han Serif SC' }, + { label: '文泉驿微米黑', value: 'WenQuanYi Micro Hei' } +] diff --git a/src/packages/base-widgets/text/index.tsx b/src/packages/base-widgets/text/index.tsx index d3346bf..62cc852 100644 --- a/src/packages/base-widgets/text/index.tsx +++ b/src/packages/base-widgets/text/index.tsx @@ -1,7 +1,7 @@ /* * @Author: 卜启缘 * @Date: 2021-06-01 09:45:21 - * @LastEditTime: 2021-06-12 10:06:33 + * @LastEditTime: 2021-06-14 10:17:54 * @LastEditors: 卜启缘 * @Description: * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx @@ -13,6 +13,7 @@ import { createEditorSelectProp } from '@/visual-editor/visual-editor.props' import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' +import { fontArr } from './fontArr' export default { key: 'text', @@ -21,18 +22,19 @@ export default { preview: () => 预览文本, render: ({ props, block }) => { const { registerRef } = useGlobalProperties() - const Text = () => ( + + return (
registerRef(el, block._vid)} - style={{ color: props.color, fontSize: props.size }} + style={{ color: props.color, fontSize: props.size, fontFamily: props.font }} > {props.text || '默认文本'}
) - return }, props: { text: createEditorInputProp({ label: '显示文本' }), + font: createEditorSelectProp({ label: '字体设置', options: fontArr }), color: createEditorColorProp('字体颜色'), size: createEditorSelectProp({ label: '字体大小', diff --git a/src/visual-editor/components/common/simulator.vue b/src/visual-editor/components/common/simulator.vue index 770909c..9f63b3e 100644 --- a/src/visual-editor/components/common/simulator.vue +++ b/src/visual-editor/components/common/simulator.vue @@ -1,7 +1,7 @@