perf: dragable components
This commit is contained in:
parent
43b6361515
commit
240a0bd779
|
@ -52,8 +52,13 @@ let propObj = {
|
||||||
$$('#props + table tr').reduce((prev, curr) => {
|
$$('#props + table tr').reduce((prev, curr) => {
|
||||||
const children = curr.children
|
const children = curr.children
|
||||||
const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase())
|
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'])({
|
const value = (propObj[children[2].textContent] ?? propObj['string'])({
|
||||||
label: `'${children[1].textContent}'`
|
label: `'${children[1].textContent}'`,
|
||||||
|
defaultValue
|
||||||
}).replaceAll('"', '')
|
}).replaceAll('"', '')
|
||||||
prev[key] = value
|
prev[key] = value
|
||||||
return prev
|
return prev
|
||||||
|
|
|
@ -57,8 +57,13 @@ let propObj = {
|
||||||
$$('#props + table tr').reduce((prev, curr) => {
|
$$('#props + table tr').reduce((prev, curr) => {
|
||||||
const children = curr.children
|
const children = curr.children
|
||||||
const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase())
|
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'])({
|
const value = (propObj[children[2].textContent] ?? propObj['string'])({
|
||||||
label: `'${children[1].textContent}'`
|
label: `'${children[1].textContent}'`,
|
||||||
|
defaultValue
|
||||||
}).replaceAll('"', '')
|
}).replaceAll('"', '')
|
||||||
prev[key] = value
|
prev[key] = value
|
||||||
return prev
|
return prev
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vant/touch-emulator": "^1.3.0",
|
"@vant/touch-emulator": "^1.3.0",
|
||||||
"@vueuse/core": "^5.0.2",
|
"@vueuse/core": "^5.0.3",
|
||||||
"@vueuse/integrations": "^5.0.2",
|
"@vueuse/integrations": "^5.0.3",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"dayjs": "^1.10.5",
|
"dayjs": "^1.10.5",
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-import": "^2.23.4",
|
"eslint-plugin-import": "^2.23.4",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"eslint-plugin-vue": "^7.11.0",
|
"eslint-plugin-vue": "^7.11.1",
|
||||||
"gh-pages": "^3.2.0",
|
"gh-pages": "^3.2.0",
|
||||||
"husky": "^6.0.0",
|
"husky": "^6.0.0",
|
||||||
"lint-staged": "^11.0.0",
|
"lint-staged": "^11.0.0",
|
||||||
|
|
|
@ -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({
|
export default defineComponent({
|
||||||
name: 'CompRender',
|
name: 'CompRender',
|
||||||
props: {
|
props: {
|
||||||
element: {
|
element: {
|
||||||
type: Object,
|
type: Object as PropType<VisualEditorBlockData>,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object as PropType<VisualEditorConfig>,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-12 21:29:32
|
* @Date: 2021-06-12 21:29:32
|
||||||
* @LastEditTime: 2021-06-12 22:03:43
|
* @LastEditTime: 2021-06-13 19:27:04
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 执行组件动画
|
* @Description: 执行组件动画
|
||||||
* @FilePath: \vite-vue3-lowcode\src\hooks\useAnimate.ts
|
* @FilePath: \vite-vue3-lowcode\src\hooks\useAnimate.ts
|
||||||
|
@ -9,30 +9,47 @@
|
||||||
|
|
||||||
import { Animation } from '@/visual-editor/visual-editor.utils'
|
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]
|
animations = Array.isArray(animations) ? animations : [animations]
|
||||||
|
|
||||||
const play = (animate: Animation) =>
|
const play = (animate: Animation) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
if (animateEl) {
|
if (animateEl) {
|
||||||
const animationName = `animate__${animate.value}`
|
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('--animate-duration', `${animate.duration}s`)
|
||||||
animateEl.style.setProperty('--animate-delay', `${animate.delay}s`)
|
animateEl.style.setProperty('animation-delay', `${animate.delay}s`)
|
||||||
animateEl.style.setProperty(
|
animateEl.style.setProperty(
|
||||||
'animation-iteration-count',
|
'animation-iteration-count',
|
||||||
`${animate.infinite ? 'infinite' : animate.count}`
|
`${animate.infinite ? 'infinite' : animate.count}`
|
||||||
)
|
)
|
||||||
|
animateEl?.classList.add(`${prefixCls}animated`, animationName)
|
||||||
|
}
|
||||||
|
|
||||||
// 动画结束时,删除类名
|
// 动画结束时,删除类名
|
||||||
const handleAnimationEnd = (event?: AnimationEvent) => {
|
const handleAnimationEnd = (event?: AnimationEvent) => {
|
||||||
event?.stopPropagation()
|
event?.stopPropagation()
|
||||||
animateEl.classList.remove(`animate__animated`, animationName)
|
animateEl.classList.remove(`${prefixCls}animated`, animationName)
|
||||||
animateEl.removeEventListener('animationend', handleAnimationEnd)
|
animateEl.removeEventListener('animationend', handleAnimationEnd)
|
||||||
resolve('animation end')
|
resolve('animation end')
|
||||||
}
|
}
|
||||||
|
|
||||||
animateEl?.classList.add(`animate__animated`, animationName)
|
setAnimate()
|
||||||
|
|
||||||
animateEl?.addEventListener('animationend', handleAnimationEnd, { once: true })
|
animateEl?.addEventListener('animationend', handleAnimationEnd, { once: true })
|
||||||
|
// animateEl?.addEventListener('animationcancel', handleAnimationEnd, { once: true })
|
||||||
} else {
|
} else {
|
||||||
resolve('动画执行失败!执行动画元素不存在!')
|
resolve('动画执行失败!执行动画元素不存在!')
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,23 @@ import {
|
||||||
createEditorSelectProp
|
createEditorSelectProp
|
||||||
} from '@/visual-editor/visual-editor.props'
|
} from '@/visual-editor/visual-editor.props'
|
||||||
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||||
|
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
key: 'divider',
|
key: 'divider',
|
||||||
moduleName: 'baseWidgets',
|
moduleName: 'baseWidgets',
|
||||||
label: '分割线',
|
label: '分割线',
|
||||||
preview: () => <Divider style="width:190px">文本</Divider>,
|
preview: () => <Divider style="width:190px">文本</Divider>,
|
||||||
render: ({ props }) => {
|
render: ({ props, block }) => {
|
||||||
const style = `color:${props['text-color']};borderColor:${props['divider-color']}`
|
const { registerRef } = useGlobalProperties()
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
color: props['text-color'],
|
||||||
|
borderColor: props['divider-color']
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Divider {...props} style={style}>
|
<Divider ref={(el) => registerRef(el, block._vid)} {...props} style={style}>
|
||||||
{{
|
{{
|
||||||
default: () => props.text
|
default: () => props.text
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-01 09:45:21
|
* @Date: 2021-06-01 09:45:21
|
||||||
* @LastEditTime: 2021-06-12 09:55:10
|
* @LastEditTime: 2021-06-14 10:31:27
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 图片组件
|
* @Description: 图片组件
|
||||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx
|
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx
|
||||||
|
@ -32,8 +32,8 @@ export default {
|
||||||
),
|
),
|
||||||
render: ({ props, block }) => {
|
render: ({ props, block }) => {
|
||||||
const { registerRef } = useGlobalProperties()
|
const { registerRef } = useGlobalProperties()
|
||||||
const ImageComp = () => <Image ref={(el) => registerRef(el, block._vid)} {...props} />
|
|
||||||
return <ImageComp></ImageComp>
|
return <Image ref={(el) => registerRef(el, block._vid)} {...props} />
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
src: createEditorInputProp({
|
src: createEditorInputProp({
|
||||||
|
|
|
@ -13,6 +13,11 @@ export default {
|
||||||
render: ({ model, size, block, props, custom }) => {
|
render: ({ model, size, block, props, custom }) => {
|
||||||
const { registerRef } = useGlobalProperties()
|
const { registerRef } = useGlobalProperties()
|
||||||
|
|
||||||
|
let rules = []
|
||||||
|
try {
|
||||||
|
rules = JSON.parse(props.rules)
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
ref={(el) => registerRef(el, block._vid)}
|
ref={(el) => registerRef(el, block._vid)}
|
||||||
|
@ -20,6 +25,7 @@ export default {
|
||||||
{...props}
|
{...props}
|
||||||
{...model.default}
|
{...model.default}
|
||||||
v-model={props.modelValue}
|
v-model={props.modelValue}
|
||||||
|
rules={rules}
|
||||||
style={{
|
style={{
|
||||||
width: size.width ? `${size.width}px` : null
|
width: size.width ? `${size.width}px` : null
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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: '是否开启文本换行,只在禁用滚动时生效' })
|
||||||
|
})
|
|
@ -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: () => (
|
||||||
|
<NoticeBar
|
||||||
|
style={{ width: '180px' }}
|
||||||
|
leftIcon={'volume-o'}
|
||||||
|
text={'在代码阅读过程中人们说脏话的频率是衡量代码质量的唯一标准。'}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
render: ({ block, props }) => {
|
||||||
|
const { registerRef } = useGlobalProperties()
|
||||||
|
|
||||||
|
return <NoticeBar ref={(el) => registerRef(el, block._vid)} {...props} />
|
||||||
|
},
|
||||||
|
props: createFieldProps(),
|
||||||
|
resize: {
|
||||||
|
width: true
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
default: '绑定字段'
|
||||||
|
}
|
||||||
|
} as VisualEditorComponent
|
|
@ -49,7 +49,7 @@ export default {
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</Field>
|
</Field>
|
||||||
<Popup v-model={[state.showPicker, 'show', ['modifier']]} position={'bottom'}>
|
<Popup v-model={[state.showPicker, 'show']} position={'bottom'}>
|
||||||
<Picker
|
<Picker
|
||||||
ref={(el) => registerRef(el, block._vid)}
|
ref={(el) => registerRef(el, block._vid)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -11,9 +11,11 @@ export default {
|
||||||
key: 'process',
|
key: 'process',
|
||||||
moduleName: 'baseWidgets',
|
moduleName: 'baseWidgets',
|
||||||
label: '进度条',
|
label: '进度条',
|
||||||
preview: () => <Progress style="width:190px" percentage={0} />,
|
preview: () => <Progress style="width:190px" percentage={50} />,
|
||||||
render: ({ props }) => {
|
render: ({ props }) => {
|
||||||
return <Progress {...props} pivotText={props.pivotText || undefined} />
|
const RenderProgress = () => <Progress {...props} pivotText={props.pivotText || undefined} />
|
||||||
|
|
||||||
|
return <RenderProgress />
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
percentage: createEditorInputNumberProp({ label: '进度百分比', defaultValue: 50 }),
|
percentage: createEditorInputNumberProp({ label: '进度百分比', defaultValue: 50 }),
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
export default {
|
export default {
|
||||||
key: 'rate',
|
key: 'rate',
|
||||||
moduleName: 'baseWidgets',
|
moduleName: 'baseWidgets',
|
||||||
label: '表单项类型 - 单选框',
|
label: '表单项类型 - 评分',
|
||||||
preview: () => (
|
preview: () => (
|
||||||
<Field
|
<Field
|
||||||
name="rate"
|
name="rate"
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
export default {
|
export default {
|
||||||
key: 'stepper',
|
key: 'stepper',
|
||||||
moduleName: 'baseWidgets',
|
moduleName: 'baseWidgets',
|
||||||
label: '表单项类型 - 单选框',
|
label: '表单项类型 - 步进器',
|
||||||
preview: () => (
|
preview: () => (
|
||||||
<Field
|
<Field
|
||||||
name="stepper"
|
name="stepper"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-06-14 12:24:12
|
||||||
|
* @LastEditTime: 2021-06-14 18:43:21
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\createFieldProps.ts
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
createEditorInputProp,
|
||||||
|
createEditorSwitchProp,
|
||||||
|
createEditorCrossSortableProp
|
||||||
|
} from '@/visual-editor/visual-editor.props'
|
||||||
|
|
||||||
|
export const createFieldProps = () => ({
|
||||||
|
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 })
|
||||||
|
})
|
|
@ -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: () => (
|
||||||
|
<Swipe style={{ width: '180px', height: '80%' }} indicatorColor={'white'}>
|
||||||
|
<SwipeItem style={swipeItemStyle}>1</SwipeItem>
|
||||||
|
<SwipeItem style={swipeItemStyle}>2</SwipeItem>
|
||||||
|
<SwipeItem style={swipeItemStyle}>3</SwipeItem>
|
||||||
|
<SwipeItem style={swipeItemStyle}>4</SwipeItem>
|
||||||
|
</Swipe>
|
||||||
|
),
|
||||||
|
render: ({ block, props }) => {
|
||||||
|
const { registerRef } = useGlobalProperties()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Swipe ref={(el) => registerRef(el, block._vid)} {...props}>
|
||||||
|
{props.images?.map((item) => (
|
||||||
|
<>
|
||||||
|
<SwipeItem key={item}>
|
||||||
|
<img src={item} />
|
||||||
|
</SwipeItem>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</Swipe>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
props: createFieldProps(),
|
||||||
|
resize: {
|
||||||
|
width: true
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
default: '绑定字段'
|
||||||
|
}
|
||||||
|
} as VisualEditorComponent
|
|
@ -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' }
|
||||||
|
]
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-01 09:45:21
|
* @Date: 2021-06-01 09:45:21
|
||||||
* @LastEditTime: 2021-06-12 10:06:33
|
* @LastEditTime: 2021-06-14 10:17:54
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description:
|
* @Description:
|
||||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx
|
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx
|
||||||
|
@ -13,6 +13,7 @@ import {
|
||||||
createEditorSelectProp
|
createEditorSelectProp
|
||||||
} from '@/visual-editor/visual-editor.props'
|
} from '@/visual-editor/visual-editor.props'
|
||||||
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||||
|
import { fontArr } from './fontArr'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
key: 'text',
|
key: 'text',
|
||||||
|
@ -21,18 +22,19 @@ export default {
|
||||||
preview: () => <span>预览文本</span>,
|
preview: () => <span>预览文本</span>,
|
||||||
render: ({ props, block }) => {
|
render: ({ props, block }) => {
|
||||||
const { registerRef } = useGlobalProperties()
|
const { registerRef } = useGlobalProperties()
|
||||||
const Text = () => (
|
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
ref={(el) => registerRef(el, block._vid)}
|
ref={(el) => registerRef(el, block._vid)}
|
||||||
style={{ color: props.color, fontSize: props.size }}
|
style={{ color: props.color, fontSize: props.size, fontFamily: props.font }}
|
||||||
>
|
>
|
||||||
{props.text || '默认文本'}
|
{props.text || '默认文本'}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
return <Text></Text>
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
text: createEditorInputProp({ label: '显示文本' }),
|
text: createEditorInputProp({ label: '显示文本' }),
|
||||||
|
font: createEditorSelectProp({ label: '字体设置', options: fontArr }),
|
||||||
color: createEditorColorProp('字体颜色'),
|
color: createEditorColorProp('字体颜色'),
|
||||||
size: createEditorSelectProp({
|
size: createEditorSelectProp({
|
||||||
label: '字体大小',
|
label: '字体大小',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-01 13:30:22
|
* @Date: 2021-06-01 13:30:22
|
||||||
* @LastEditTime: 2021-06-12 18:29:28
|
* @LastEditTime: 2021-06-14 00:21:31
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 手机模拟器
|
* @Description: 手机模拟器
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\common\simulator.vue
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\common\simulator.vue
|
||||||
|
|
|
@ -151,7 +151,7 @@ export const useTools = () => {
|
||||||
icon: 'el-icon-position',
|
icon: 'el-icon-position',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
localStorage.setItem(localKey, JSON.stringify(jsonData))
|
localStorage.setItem(localKey, JSON.stringify(jsonData))
|
||||||
window.open(location.href.replace('/#/', '/preview/'))
|
window.open(location.href.replace('/#/', '/preview/#/'))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-11 18:08:01
|
* @Date: 2021-06-11 18:08:01
|
||||||
* @LastEditTime: 2021-06-12 22:07:05
|
* @LastEditTime: 2021-06-13 18:32:53
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 动画组件
|
* @Description: 动画组件
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\animate\Animate.tsx
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\animate\Animate.tsx
|
||||||
|
@ -92,10 +92,10 @@ export const Animate = defineComponent({
|
||||||
<>
|
<>
|
||||||
{currentBlock.value.animations?.map((item, index) => (
|
{currentBlock.value.animations?.map((item, index) => (
|
||||||
<ElAlert
|
<ElAlert
|
||||||
onClose={() => delAnimate(index)}
|
key={item.value}
|
||||||
type={'info'}
|
type={'info'}
|
||||||
style={{ marginTop: '12px' }}
|
style={{ marginTop: '12px' }}
|
||||||
key={item.value}
|
onClose={() => delAnimate(index)}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
title: () => (
|
title: () => (
|
||||||
|
@ -164,9 +164,10 @@ export const Animate = defineComponent({
|
||||||
<div v-show={!state.isAddAnimates}>
|
<div v-show={!state.isAddAnimates}>
|
||||||
<ElButton
|
<ElButton
|
||||||
type={'primary'}
|
type={'primary'}
|
||||||
onClick={() => (state.isAddAnimates = true)}
|
disabled={!currentBlock.value.animations}
|
||||||
plain
|
plain
|
||||||
icon={'el-icon-plus'}
|
icon={'el-icon-plus'}
|
||||||
|
onClick={() => (state.isAddAnimates = true)}
|
||||||
>
|
>
|
||||||
添加动画
|
添加动画
|
||||||
</ElButton>
|
</ElButton>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-10 16:23:06
|
* @Date: 2021-06-10 16:23:06
|
||||||
* @LastEditTime: 2021-06-10 16:46:36
|
* @LastEditTime: 2021-06-14 17:22:11
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 组件属性编辑器
|
* @Description: 组件属性编辑器
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\AttrEditor.tsx
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\AttrEditor.tsx
|
||||||
*/
|
*/
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import {
|
import {
|
||||||
|
@ -19,7 +19,7 @@ import {
|
||||||
ElPopover
|
ElPopover
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props'
|
import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props'
|
||||||
import { TablePropEditor } from '../'
|
import { TablePropEditor, CrossSortableOptionsEditor } from '../'
|
||||||
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
|
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
|
||||||
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ export const AttrEditor = defineComponent({
|
||||||
[VisualEditorPropsType.inputNumber]: () => <ElInputNumber v-model={propObj[prop]} />,
|
[VisualEditorPropsType.inputNumber]: () => <ElInputNumber v-model={propObj[prop]} />,
|
||||||
[VisualEditorPropsType.switch]: () => <ElSwitch v-model={propObj[prop]} />,
|
[VisualEditorPropsType.switch]: () => <ElSwitch v-model={propObj[prop]} />,
|
||||||
[VisualEditorPropsType.color]: () => <ElColorPicker v-model={propObj[prop]} />,
|
[VisualEditorPropsType.color]: () => <ElColorPicker v-model={propObj[prop]} />,
|
||||||
|
[VisualEditorPropsType.crossSortable]: () => (
|
||||||
|
<CrossSortableOptionsEditor v-model={propObj[prop]} />
|
||||||
|
),
|
||||||
[VisualEditorPropsType.select]: () => (
|
[VisualEditorPropsType.select]: () => (
|
||||||
<ElSelect v-model={propObj[prop]} valueKey={'value'} multiple={propConfig.multiple}>
|
<ElSelect v-model={propObj[prop]} valueKey={'value'} multiple={propConfig.multiple}>
|
||||||
{propConfig.options?.map((opt) => (
|
{propConfig.options?.map((opt) => (
|
||||||
|
@ -91,20 +94,30 @@ export const AttrEditor = defineComponent({
|
||||||
content.push(
|
content.push(
|
||||||
...Object.entries(component.props || {}).map(([propName, propConfig]) => (
|
...Object.entries(component.props || {}).map(([propName, propConfig]) => (
|
||||||
<>
|
<>
|
||||||
<ElFormItem key={currentBlock.value._vid + propName}>
|
<ElFormItem
|
||||||
|
key={currentBlock.value._vid + propName}
|
||||||
|
style={
|
||||||
|
propConfig.labelPosition == 'top'
|
||||||
|
? {
|
||||||
|
display: 'flex',
|
||||||
|
'flex-direction': 'column',
|
||||||
|
'align-items': 'flex-start'
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
{{
|
{{
|
||||||
label: () =>
|
label: () => (
|
||||||
propConfig.tips ? (
|
|
||||||
<>
|
<>
|
||||||
|
{propConfig.tips && (
|
||||||
<ElPopover width={200} trigger={'hover'} content={propConfig.tips}>
|
<ElPopover width={200} trigger={'hover'} content={propConfig.tips}>
|
||||||
{{
|
{{
|
||||||
reference: () => <i class={'el-icon-warning-outline'}></i>
|
reference: () => <i class={'el-icon-warning-outline'}></i>
|
||||||
}}
|
}}
|
||||||
</ElPopover>
|
</ElPopover>
|
||||||
|
)}
|
||||||
{propConfig.label}
|
{propConfig.label}
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
propConfig.label
|
|
||||||
),
|
),
|
||||||
default: () => renderEditor(propName, propConfig)
|
default: () => renderEditor(propName, propConfig)
|
||||||
}}
|
}}
|
||||||
|
@ -117,7 +130,7 @@ export const AttrEditor = defineComponent({
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ElForm size="mini" label-position="left">
|
<ElForm size="mini" labelPosition={'left'}>
|
||||||
{content}
|
{content}
|
||||||
</ElForm>
|
</ElForm>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-06-14 15:00:45
|
||||||
|
* @LastEditTime: 2021-06-14 17:41:14
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description: 可以拖拽排序的选项列表
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\cross-sortable-options\cross-sortable-options.tsx
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { defineComponent, reactive, computed, PropType } from 'vue'
|
||||||
|
import Draggable from 'vuedraggable'
|
||||||
|
import { ElInput } from 'element-plus'
|
||||||
|
import { useVModel } from '@vueuse/core'
|
||||||
|
|
||||||
|
export const CrossSortableOptionsEditor = defineComponent({
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const state = reactive({
|
||||||
|
list: useVModel(props, 'modelValue', emit),
|
||||||
|
drag: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const dragOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
animation: 200,
|
||||||
|
group: 'description',
|
||||||
|
disabled: false,
|
||||||
|
ghostClass: 'ghost'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<Draggable
|
||||||
|
tag="ul"
|
||||||
|
list={state.list}
|
||||||
|
class="list-group"
|
||||||
|
component-data={{
|
||||||
|
tag: 'ul',
|
||||||
|
type: 'transition-group',
|
||||||
|
name: !state.drag ? 'flip-list' : null
|
||||||
|
}}
|
||||||
|
handle=".handle"
|
||||||
|
{...dragOptions.value}
|
||||||
|
itemKey={''}
|
||||||
|
onStart={() => (state.drag = true)}
|
||||||
|
onEnd={() => (state.drag = false)}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
item: ({ element, index }) => (
|
||||||
|
<div class={'flex items-center justify-between'}>
|
||||||
|
<i class={'el-icon-s-grid handle'}></i>
|
||||||
|
<ElInput
|
||||||
|
v-model={state.list[index]}
|
||||||
|
class={'m-12px'}
|
||||||
|
style={{ width: '270px' }}
|
||||||
|
></ElInput>
|
||||||
|
<div class={'flex flex-col'}>
|
||||||
|
<i class={'el-icon-circle-plus-outline'} onClick={() => state.list.push('')}></i>
|
||||||
|
<i class={'el-icon-remove-outline'} onClick={() => state.list.splice(index, 1)}></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Draggable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,10 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* @name: index
|
* @Author: 卜启缘
|
||||||
* @author: 卜启缘
|
* @Date: 2021-06-12 22:18:48
|
||||||
* @date: 2021/5/30 10:57
|
* @LastEditTime: 2021-06-14 16:58:34
|
||||||
* @description:index
|
* @LastEditors: 卜启缘
|
||||||
* @update: 2021/5/30 10:57
|
* @Description:
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\index.ts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { TablePropEditor } from './table-prop-editor/table-prop-editor'
|
export { TablePropEditor } from './table-prop-editor/table-prop-editor'
|
||||||
export { AttrEditor } from './attr-editor/AttrEditor'
|
export { AttrEditor } from './attr-editor/AttrEditor'
|
||||||
export { Animate } from './animate/Animate'
|
export { Animate } from './animate/Animate'
|
||||||
|
export { CrossSortableOptionsEditor } from './cross-sortable-options/cross-sortable-options'
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-06-13 22:07:29
|
||||||
|
* @LastEditTime: 2021-06-14 18:18:51
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description: 当前页面配置
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\page-setting\pageSetting.tsx
|
||||||
|
*/
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* @name: index.common
|
|
||||||
* @author: 卜启缘
|
|
||||||
* @date: 2021/5/3 16:05
|
|
||||||
* @description:index.common
|
|
||||||
* @update: 2021/5/3 16:05
|
|
||||||
*/
|
|
||||||
body {
|
|
||||||
.el-form-item__label {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.el-form-item--mini .el-form-item__content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -67,6 +67,16 @@ $boxShadow: -2px 0 4px 0 rgb(0 0 0 / 10%);
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item--mini .el-form-item__content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-01 13:22:14
|
* @Date: 2021-06-01 13:22:14
|
||||||
* @LastEditTime: 2021-06-12 19:25:26
|
* @LastEditTime: 2021-06-13 21:26:49
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 属性编辑器
|
* @Description: 属性编辑器
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\index.tsx
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\index.tsx
|
||||||
|
@ -10,11 +10,7 @@
|
||||||
|
|
||||||
import { defineComponent, reactive } from 'vue'
|
import { defineComponent, reactive } from 'vue'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import './index.common.scss'
|
|
||||||
import { ElTabPane, ElTabs } from 'element-plus'
|
import { ElTabPane, ElTabs } from 'element-plus'
|
||||||
|
|
||||||
console.log(styles, 'styles')
|
|
||||||
|
|
||||||
import MonacoEditor from '../common/monaco-editor/MonacoEditor'
|
import MonacoEditor from '../common/monaco-editor/MonacoEditor'
|
||||||
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
||||||
import { AttrEditor, Animate } from './components'
|
import { AttrEditor, Animate } from './components'
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
|
/*
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-05-04 05:36:58
|
||||||
|
* @LastEditTime: 2021-06-14 10:02:47
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx
|
||||||
|
*/
|
||||||
import { defineComponent, PropType } from 'vue'
|
import { defineComponent, PropType } from 'vue'
|
||||||
import { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils'
|
import { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CompRender',
|
name: 'CompRender',
|
||||||
|
@ -9,7 +17,7 @@ export default defineComponent({
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object as PropType<VisualEditorConfig>,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -94,9 +94,9 @@ export default defineComponent({
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
|
|
||||||
&.isDrag div[data-draggable='true'] {
|
// &.isDrag div[data-draggable='true'] {
|
||||||
padding: 8px 0;
|
// padding: 2px 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
&.isDrag:not(.no-child) :deep(.list-group-item.has-slot) {
|
&.isDrag:not(.no-child) :deep(.list-group-item.has-slot) {
|
||||||
@include showContainerBorder;
|
@include showContainerBorder;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<DraggableTransitionGroup v-model:drag="drag" v-model="currentPage.blocks">
|
<DraggableTransitionGroup
|
||||||
|
v-model:drag="drag"
|
||||||
|
v-model="currentPage.blocks"
|
||||||
|
style="min-height: 500px"
|
||||||
|
>
|
||||||
<template #item="{ element: outElement }">
|
<template #item="{ element: outElement }">
|
||||||
<div
|
<div
|
||||||
class="list-group-item"
|
class="list-group-item"
|
||||||
|
@ -14,6 +18,7 @@
|
||||||
@mousedown="selectComp(outElement)"
|
@mousedown="selectComp(outElement)"
|
||||||
>
|
>
|
||||||
<comp-render
|
<comp-render
|
||||||
|
:key="outElement._vid"
|
||||||
:config="visualConfig"
|
:config="visualConfig"
|
||||||
:element="outElement"
|
:element="outElement"
|
||||||
:style="{
|
:style="{
|
||||||
|
@ -93,6 +98,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 给当前点击的组件设置聚焦
|
||||||
const handleSlotsFocus = (block, _vid) => {
|
const handleSlotsFocus = (block, _vid) => {
|
||||||
const slots = block.props?.slots || {}
|
const slots = block.props?.slots || {}
|
||||||
if (Object.keys(slots).length > 0) {
|
if (Object.keys(slots).length > 0) {
|
||||||
|
@ -112,6 +118,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 选择要操作的组件
|
||||||
const selectComp = (element) => {
|
const selectComp = (element) => {
|
||||||
setCurrentBlock(element)
|
setCurrentBlock(element)
|
||||||
currentPage.value.blocks.forEach((block) => {
|
currentPage.value.blocks.forEach((block) => {
|
||||||
|
@ -165,7 +172,10 @@ export default defineComponent({
|
||||||
const index = parentBlocks.findIndex((item) => item._vid == block._vid)
|
const index = parentBlocks.findIndex((item) => item._vid == block._vid)
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
delete globalProperties.$$refs[parentBlocks[index]._vid]
|
delete globalProperties.$$refs[parentBlocks[index]._vid]
|
||||||
parentBlocks.splice(index, 1)
|
const delTarget = parentBlocks.splice(index, 1)[0]
|
||||||
|
if (delTarget.focus) {
|
||||||
|
setCurrentBlock({} as VisualEditorBlockData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
v-model:drag="isDrag"
|
v-model:drag="isDrag"
|
||||||
class="inner-draggable"
|
class="inner-draggable"
|
||||||
:class="{ slot: !slotChildren?.length }"
|
:class="{ slot: !slotChildren?.length }"
|
||||||
:data-slot="`插槽(${slotKey})\n 拖拽组件到此处${drag}`"
|
:data-slot="`插槽(${slotKey})\n 拖拽组件到此处`"
|
||||||
>
|
>
|
||||||
<template #item="{ element: innerElement }">
|
<template #item="{ element: innerElement }">
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -122,6 +122,8 @@ export const initVisualData = (): VisualData => {
|
||||||
state.currentPage = jsonData.pages['/']
|
state.currentPage = jsonData.pages['/']
|
||||||
router.replace('/')
|
router.replace('/')
|
||||||
}
|
}
|
||||||
|
const currentFocusBlock = state.currentPage.blocks.find((item) => item.focus)
|
||||||
|
setCurrentBlock(currentFocusBlock ?? ({} as VisualEditorBlockData))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置当前被操作的组件
|
// 设置当前被操作的组件
|
||||||
|
|
|
@ -4,13 +4,15 @@ export enum VisualEditorPropsType {
|
||||||
color = 'color',
|
color = 'color',
|
||||||
select = 'select',
|
select = 'select',
|
||||||
table = 'table',
|
table = 'table',
|
||||||
switch = 'switch'
|
switch = 'switch',
|
||||||
|
crossSortable = 'crossSortable'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VisualEditorProps = {
|
export type VisualEditorProps = {
|
||||||
type: VisualEditorPropsType
|
type: VisualEditorPropsType
|
||||||
label: string
|
label: string
|
||||||
tips?: string
|
tips?: string // 表单项提示
|
||||||
|
labelPosition?: string // 表单域标签的位置
|
||||||
multiple?: boolean
|
multiple?: boolean
|
||||||
defaultValue?: any
|
defaultValue?: any
|
||||||
} & {
|
} & {
|
||||||
|
@ -150,3 +152,24 @@ export function createEditorTableProp({
|
||||||
defaultValue
|
defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------CrossSortableOptions-------------------------------------------*/
|
||||||
|
|
||||||
|
interface EditorCrossSortableProp {
|
||||||
|
label: string
|
||||||
|
labelPosition: string
|
||||||
|
defaultValue?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createEditorCrossSortableProp({
|
||||||
|
label,
|
||||||
|
labelPosition,
|
||||||
|
defaultValue
|
||||||
|
}: EditorCrossSortableProp): VisualEditorProps {
|
||||||
|
return {
|
||||||
|
type: VisualEditorPropsType.crossSortable,
|
||||||
|
label,
|
||||||
|
labelPosition,
|
||||||
|
defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
36
yarn.lock
36
yarn.lock
|
@ -964,20 +964,20 @@
|
||||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.1.tgz#2287cfc3dc20e5b20aeb65c2c3a56533bdca801c"
|
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.1.tgz#2287cfc3dc20e5b20aeb65c2c3a56533bdca801c"
|
||||||
integrity sha512-g+4pzAw7PYSjARtLBoDq6DmcblX8i9KJHSCnyM5VDDFFifUaUT9iHbFpOF/KOizQ9f7QAqU2JH3Y6aXjzUMhVA==
|
integrity sha512-g+4pzAw7PYSjARtLBoDq6DmcblX8i9KJHSCnyM5VDDFFifUaUT9iHbFpOF/KOizQ9f7QAqU2JH3Y6aXjzUMhVA==
|
||||||
|
|
||||||
"@vueuse/core@^5.0.2":
|
"@vueuse/core@^5.0.3":
|
||||||
version "5.0.2"
|
version "5.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.0.2.tgz#302389f620c0d4b51fdf157012d9b5b522b605e7"
|
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.0.3.tgz#8f3170e2a51ae62fb1725c84d4cc02a7552aad0b"
|
||||||
integrity sha512-Sp9+7AL4Cg3Tx6I55WoH7zICGRlp6ZUF9NW3EU8SZTkryHm0afAjFfASMwlfV030JFeh45BdqafDOrenVmM9Cw==
|
integrity sha512-TMCL11EVMaj2Y5qdYosvuwA+i1aKrerFXs7fhNZiQiLCWxF8XsrNdxzoiaI2n12UcmSOXvd1xdyWs7Nss+p/Hg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vueuse/shared" "5.0.2"
|
"@vueuse/shared" "5.0.3"
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
|
|
||||||
"@vueuse/integrations@^5.0.2":
|
"@vueuse/integrations@^5.0.3":
|
||||||
version "5.0.2"
|
version "5.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-5.0.2.tgz#95b9f5bea831430f747d7311d9497ec9f52db3bd"
|
resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-5.0.3.tgz#64820965d068b356b4df50ed47a87adf0141f68e"
|
||||||
integrity sha512-jh9Ywz8zu2YmsSd1xeyXkuoA8fhNRkoUkzX4y/hSm2IQC2ydkD8Rk/aOvPAew5RiwndtWhXQYu5XrSMQRsYDYQ==
|
integrity sha512-c7dy7u4XTJeSfq/NnFotoUPrbkPJv/DbWwEYVW9YXXMdDvz1IxDdXUFrOu8ElM0qzGn4CuYg6Yr37uYR13MgXg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vueuse/shared" "5.0.2"
|
"@vueuse/shared" "5.0.3"
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
axios "^0.21.1"
|
axios "^0.21.1"
|
||||||
|
@ -987,10 +987,10 @@
|
||||||
qrcode "^1.4.4"
|
qrcode "^1.4.4"
|
||||||
universal-cookie "^4.0.4"
|
universal-cookie "^4.0.4"
|
||||||
|
|
||||||
"@vueuse/shared@5.0.2":
|
"@vueuse/shared@5.0.3":
|
||||||
version "5.0.2"
|
version "5.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-5.0.2.tgz#274c2bf163d25eb7fd2fc51f23088a2b7f060594"
|
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-5.0.3.tgz#31613951d5036459650ad8d47a9185e8950ea3c9"
|
||||||
integrity sha512-S1hRRmEdipjTD4DbXgPdw4ZZYebU/nDi75vNP3Ibpa1irW3NUNUKOT/TWnwRHLQvXquUtdvalhI8D9Db+czZJg==
|
integrity sha512-aY93WPygr8H/4RB8YuOmAD83Y+faq7zwW10Kd9i0kD9zf5ysVP+32j09rF/mZVtGCa0CSM8ambPZMsEhCkRbwQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
|
|
||||||
|
@ -2324,10 +2324,10 @@ eslint-plugin-prettier@^3.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
prettier-linter-helpers "^1.0.0"
|
prettier-linter-helpers "^1.0.0"
|
||||||
|
|
||||||
eslint-plugin-vue@^7.11.0:
|
eslint-plugin-vue@^7.11.1:
|
||||||
version "7.11.0"
|
version "7.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.11.0.tgz#c19b098899b7e3cd692beffbbe73611064ef1ea6"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.11.1.tgz#77eb4b44032d5cca79f9af21d06991d8694a314a"
|
||||||
integrity sha512-Qwo8wilqnOXnG9B5auEiTstyaHefyhHd5lEhhxemwXoWsAxIW2yppzuVudowC5n+qn1nMLNV9TANkTthBK7Waw==
|
integrity sha512-lbw3vkEAGqYjqd1HpPFWHXtYaS8mILTJ5KOpJfRxO3Fo7o0wCf1zD7vSOasbm6nTA9xIgvZQ4VcyGIzQXxznHw==
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-utils "^2.1.0"
|
eslint-utils "^2.1.0"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
|
|
Loading…
Reference in New Issue