Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-vue-admin
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-vue-admin
Commits
f75425d1
提交
f75425d1
authored
10月 22, 2020
作者:
vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
perf: review tinymce code
上级
9c02d8ec
隐藏空白字符变更
内嵌
并排
正在显示
25 个修改的文件
包含
270 行增加
和
457 行删除
+270
-457
Editor.vue
src/components/Tinymce/src/Editor.vue
+129
-19
getTinymce.ts
src/components/Tinymce/src/getTinymce.ts
+1
-4
helper.ts
src/components/Tinymce/src/helper.ts
+2
-73
ScriptLoader.ts
src/components/Tinymce/src/lib/ScriptLoader.ts
+0
-73
Editor.ts
src/components/Tinymce/src/lib/components/Editor.ts
+0
-111
EditorPropTypes.ts
src/components/Tinymce/src/lib/components/EditorPropTypes.ts
+0
-46
global.d.ts
src/components/Tinymce/src/lib/global.d.ts
+0
-4
index.ts
src/components/Tinymce/src/lib/index.ts
+0
-3
props.ts
src/components/Tinymce/src/props.ts
+4
-6
charts.ts
src/router/menus/modules/demo/charts.ts
+5
-5
comp.ts
src/router/menus/modules/demo/comp.ts
+11
-25
editor.ts
src/router/menus/modules/demo/editor.ts
+15
-1
excel.ts
src/router/menus/modules/demo/excel.ts
+4
-6
exception.ts
src/router/menus/modules/demo/exception.ts
+6
-6
feat.ts
src/router/menus/modules/demo/feat.ts
+13
-13
form.ts
src/router/menus/modules/demo/form.ts
+7
-7
iframe.ts
src/router/menus/modules/demo/iframe.ts
+3
-3
permission.ts
src/router/menus/modules/demo/permission.ts
+8
-8
table.ts
src/router/menus/modules/demo/table.ts
+14
-14
comp.ts
src/router/routes/modules/demo/comp.ts
+0
-26
editor.ts
src/router/routes/modules/demo/editor.ts
+27
-0
is.ts
src/utils/is.ts
+4
-0
uuid.ts
src/utils/uuid.ts
+8
-0
Editor.vue
src/views/demo/editor/tinymce/Editor.vue
+1
-1
index.vue
src/views/demo/editor/tinymce/index.vue
+8
-3
没有找到文件。
src/components/Tinymce/src/Editor.vue
浏览文件 @
f75425d1
<
template
>
<
template
>
<div
class=
"tinymce-container"
:style=
"
{ width: containerWidth }">
<div
class=
"tinymce-container"
:style=
"
{ width: containerWidth }">
<tinymce-editor
<textarea
:id=
"tinymceId"
visibility=
"hidden"
ref=
"elRef"
></textarea>
:id=
"id"
:init=
"initOptions"
:modelValue=
"tinymceContent"
@
update:modelValue=
"handleChange"
:tinymceScriptSrc=
"tinymceScriptSrc"
></tinymce-editor>
</div>
</div>
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
TinymceEditor
from
'./lib'
;
// TinyMCE vue wrapper
import
{
import
{
defineComponent
,
computed
}
from
'vue'
;
defineComponent
,
computed
,
onMounted
,
nextTick
,
ref
,
unref
,
watch
,
onUnmounted
,
onDeactivated
,
}
from
'vue'
;
import
{
basicProps
}
from
'./props'
;
import
{
basicProps
}
from
'./props'
;
import
toolbar
from
'./toolbar'
;
import
toolbar
from
'./toolbar'
;
import
plugins
from
'./plugins'
;
import
plugins
from
'./plugins'
;
import
{
getTinymce
}
from
'./getTinymce'
;
import
{
useScript
}
from
'/@/hooks/web/useScript'
;
import
{
snowUuid
}
from
'/@/utils/uuid'
;
import
{
bindHandlers
}
from
'./helper'
;
const
CDN_URL
=
'https://cdn.bootcdn.net/ajax/libs/tinymce/5.5.1'
;
const
CDN_URL
=
'https://cdn.bootcdn.net/ajax/libs/tinymce/5.5.1'
;
const
tinymceScriptSrc
=
`
${
CDN_URL
}
/tinymce.min.js`
;
const
tinymceScriptSrc
=
`
${
CDN_URL
}
/tinymce.min.js`
;
export
default
defineComponent
({
export
default
defineComponent
({
name
:
'Tinymce'
,
name
:
'Tinymce'
,
components
:
{
TinymceEditor
},
props
:
basicProps
,
props
:
basicProps
,
setup
(
props
,
{
emit
})
{
emits
:
[
'change'
,
'update:modelValue'
],
setup
(
props
,
{
emit
,
attrs
})
{
const
editorRef
=
ref
<
any
>
(
null
);
const
elRef
=
ref
<
Nullable
<
HTMLElement
>>
(
null
);
const
tinymceId
=
computed
(()
=>
{
return
snowUuid
(
'tiny-vue'
);
});
const
tinymceContent
=
computed
(()
=>
{
const
tinymceContent
=
computed
(()
=>
{
return
props
.
v
alue
;
return
props
.
modelV
alue
;
});
});
function
handleChange
(
value
:
string
)
{
emit
(
'change'
,
value
);
}
const
containerWidth
=
computed
(()
=>
{
const
containerWidth
=
computed
(()
=>
{
const
width
=
props
.
width
;
const
width
=
props
.
width
;
// Test matches `100`, `'100'`
if
(
/^
[\d]
+
(\.[\d]
+
)?
$/
.
test
(
width
.
toString
()))
{
if
(
/^
[\d]
+
(\.[\d]
+
)?
$/
.
test
(
width
.
toString
()))
{
return
`
${
width
}
px`
;
return
`
${
width
}
px`
;
}
}
return
width
;
return
width
;
});
});
const
initOptions
=
computed
(()
=>
{
const
initOptions
=
computed
(()
=>
{
const
{
id
,
height
,
menubar
}
=
props
;
const
{
height
,
menubar
}
=
props
;
return
{
return
{
selector
:
`#
${
id
}
`
,
selector
:
`#
${
unref
(
tinymceId
)
}
`
,
height
:
height
,
height
:
height
,
toolbar
:
toolbar
,
toolbar
:
toolbar
,
theme
:
'silver'
,
menubar
:
menubar
,
menubar
:
menubar
,
plugins
:
plugins
,
plugins
:
plugins
,
// 语言包
// 语言包
language_url
:
'resource/tinymce/langs/zh_CN.js'
,
language_url
:
'resource/tinymce/langs/zh_CN.js'
,
// 中文
// 中文
language
:
'zh_CN'
,
language
:
'zh_CN'
,
default_link_target
:
'_blank'
,
link_title
:
false
,
advlist_bullet_styles
:
'square'
,
advlist_number_styles
:
'default'
,
object_resizing
:
false
,
setup
:
(
editor
:
any
)
=>
{
editorRef
.
value
=
editor
;
editor
.
on
(
'init'
,
(
e
:
Event
)
=>
initSetup
(
e
));
},
};
};
});
});
return
{
containerWidth
,
initOptions
,
tinymceContent
,
handleChange
,
tinymceScriptSrc
};
const
{
toPromise
}
=
useScript
({
src
:
tinymceScriptSrc
,
});
watch
(
()
=>
attrs
.
disabled
,
()
=>
{
const
editor
=
unref
(
editorRef
);
if
(
!
editor
)
return
;
editor
.
setMode
(
attrs
.
disabled
?
'readonly'
:
'design'
);
}
);
onMounted
(()
=>
{
nextTick
(()
=>
{
init
();
});
});
onUnmounted
(()
=>
{
destory
();
});
onDeactivated
(()
=>
{
destory
();
});
function
destory
()
{
if
(
getTinymce
()
!==
null
)
{
getTinymce
().
remove
(
unref
(
editorRef
));
}
}
function
init
()
{
toPromise
().
then
(()
=>
{
initEditor
();
});
}
function
initEditor
()
{
getTinymce
().
init
(
unref
(
initOptions
));
}
function
initSetup
(
e
:
Event
)
{
const
editor
=
unref
(
editorRef
);
if
(
!
editor
)
return
;
const
value
=
props
.
modelValue
||
''
;
editor
.
setContent
(
value
);
bindModelHandlers
(
editor
);
bindHandlers
(
e
,
attrs
,
unref
(
editorRef
));
}
function
bindModelHandlers
(
editor
:
any
)
{
const
modelEvents
=
attrs
.
modelEvents
?
attrs
.
modelEvents
:
null
;
const
normalizedEvents
=
Array
.
isArray
(
modelEvents
)
?
modelEvents
.
join
(
' '
)
:
modelEvents
;
watch
(
()
=>
props
.
modelValue
,
(
val
:
string
,
prevVal
:
string
)
=>
{
if
(
editor
&&
typeof
val
===
'string'
&&
val
!==
prevVal
&&
val
!==
editor
.
getContent
({
format
:
attrs
.
outputFormat
})
)
{
editor
.
setContent
(
val
);
}
}
);
editor
.
on
(
normalizedEvents
?
normalizedEvents
:
'change keyup undo redo'
,
()
=>
{
emit
(
'update:modelValue'
,
editor
.
getContent
({
format
:
attrs
.
outputFormat
}));
});
}
function
handleChange
(
value
:
string
)
{
emit
(
'change'
,
value
);
}
return
{
containerWidth
,
initOptions
,
tinymceContent
,
handleChange
,
tinymceScriptSrc
,
elRef
,
tinymceId
,
};
},
},
});
});
</
script
>
</
script
>
...
...
src/components/Tinymce/src/
lib/TinyMCE
.ts
→
src/components/Tinymce/src/
getTinymce
.ts
浏览文件 @
f75425d1
const
getGlobal
=
():
any
=>
(
typeof
window
!==
'undefined'
?
window
:
global
);
const
getGlobal
=
():
any
=>
(
typeof
window
!==
'undefined'
?
window
:
global
);
const
getTinymce
=
()
=>
{
export
const
getTinymce
=
()
=>
{
const
global
=
getGlobal
();
const
global
=
getGlobal
();
return
global
&&
global
.
tinymce
?
global
.
tinymce
:
null
;
return
global
&&
global
.
tinymce
?
global
.
tinymce
:
null
;
};
};
export
{
getTinymce
};
src/components/Tinymce/src/
lib/Utils
.ts
→
src/components/Tinymce/src/
helper
.ts
浏览文件 @
f75425d1
import
{
ComponentPublicInstance
}
from
'vue'
;
const
validEvents
=
[
const
validEvents
=
[
'onActivate'
,
'onActivate'
,
'onAddUndo'
,
'onAddUndo'
,
...
@@ -62,12 +60,12 @@ const validEvents = [
...
@@ -62,12 +60,12 @@ const validEvents = [
'onShow'
,
'onShow'
,
'onSubmit'
,
'onSubmit'
,
'onUndo'
,
'onUndo'
,
'onVisualAid'
'onVisualAid'
,
];
];
const
isValidKey
=
(
key
:
string
)
=>
validEvents
.
indexOf
(
key
)
!==
-
1
;
const
isValidKey
=
(
key
:
string
)
=>
validEvents
.
indexOf
(
key
)
!==
-
1
;
const
bindHandlers
=
(
initEvent
:
Event
,
listeners
:
any
,
editor
:
any
):
void
=>
{
export
const
bindHandlers
=
(
initEvent
:
Event
,
listeners
:
any
,
editor
:
any
):
void
=>
{
Object
.
keys
(
listeners
)
Object
.
keys
(
listeners
)
.
filter
(
isValidKey
)
.
filter
(
isValidKey
)
.
forEach
((
key
:
string
)
=>
{
.
forEach
((
key
:
string
)
=>
{
...
@@ -81,71 +79,3 @@ const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => {
...
@@ -81,71 +79,3 @@ const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => {
}
}
});
});
};
};
const
bindModelHandlers
=
(
ctx
:
ComponentPublicInstance
,
editor
:
any
)
=>
{
const
modelEvents
=
ctx
.
$props
.
modelEvents
?
ctx
.
$props
.
modelEvents
:
null
;
const
normalizedEvents
=
Array
.
isArray
(
modelEvents
)
?
modelEvents
.
join
(
' '
)
:
modelEvents
;
// @ts-ignore
ctx
.
$watch
(
'modelValue'
,
(
val
:
string
,
prevVal
:
string
)
=>
{
if
(
editor
&&
typeof
val
===
'string'
&&
val
!==
prevVal
&&
val
!==
editor
.
getContent
({
format
:
ctx
.
$props
.
outputFormat
}))
{
editor
.
setContent
(
val
);
}
});
editor
.
on
(
normalizedEvents
?
normalizedEvents
:
'change keyup undo redo'
,
()
=>
{
ctx
.
$emit
(
'update:modelValue'
,
editor
.
getContent
({
format
:
ctx
.
$props
.
outputFormat
}));
});
};
const
initEditor
=
(
initEvent
:
Event
,
ctx
:
ComponentPublicInstance
,
editor
:
any
)
=>
{
const
value
=
ctx
.
$props
.
modelValue
?
ctx
.
$props
.
modelValue
:
''
;
const
initialValue
=
ctx
.
$props
.
initialValue
?
ctx
.
$props
.
initialValue
:
''
;
editor
.
setContent
(
value
||
initialValue
);
// checks if the v-model shorthand is used (which sets an v-on:input listener) and then binds either
// specified the events or defaults to "change keyup" event and emits the editor content on that event
if
(
ctx
.
$attrs
[
'onUpdate:modelValue'
])
{
bindModelHandlers
(
ctx
,
editor
);
}
bindHandlers
(
initEvent
,
ctx
.
$attrs
,
editor
);
};
let
unique
=
0
;
const
uuid
=
(
prefix
:
string
):
string
=>
{
const
time
=
Date
.
now
();
const
random
=
Math
.
floor
(
Math
.
random
()
*
1000000000
);
unique
++
;
return
prefix
+
'_'
+
random
+
unique
+
String
(
time
);
};
const
isTextarea
=
(
element
:
Element
|
null
):
element
is
HTMLTextAreaElement
=>
{
return
element
!==
null
&&
element
.
tagName
.
toLowerCase
()
===
'textarea'
;
};
const
normalizePluginArray
=
(
plugins
?:
string
|
string
[]):
string
[]
=>
{
if
(
typeof
plugins
===
'undefined'
||
plugins
===
''
)
{
return
[];
}
return
Array
.
isArray
(
plugins
)
?
plugins
:
plugins
.
split
(
' '
);
};
const
mergePlugins
=
(
initPlugins
:
string
|
string
[],
inputPlugins
?:
string
|
string
[])
=>
normalizePluginArray
(
initPlugins
).
concat
(
normalizePluginArray
(
inputPlugins
));
const
isNullOrUndefined
=
(
value
:
any
):
value
is
null
|
undefined
=>
value
===
null
||
value
===
undefined
;
export
{
bindHandlers
,
bindModelHandlers
,
initEditor
,
uuid
,
isTextarea
,
mergePlugins
,
isNullOrUndefined
};
\ No newline at end of file
src/components/Tinymce/src/lib/ScriptLoader.ts
deleted
100644 → 0
浏览文件 @
9c02d8ec
import
{
uuid
}
from
'./Utils'
;
export
type
callbackFn
=
()
=>
void
;
export
interface
IStateObj
{
listeners
:
callbackFn
[];
scriptId
:
string
;
scriptLoaded
:
boolean
;
}
const
createState
=
():
IStateObj
=>
{
return
{
listeners
:
[],
scriptId
:
uuid
(
'tiny-script'
),
scriptLoaded
:
false
};
};
interface
ScriptLoader
{
load
:
(
doc
:
Document
,
url
:
string
,
callback
:
callbackFn
)
=>
void
;
reinitialize
:
()
=>
void
;
}
const
CreateScriptLoader
=
():
ScriptLoader
=>
{
let
state
:
IStateObj
=
createState
();
const
injectScriptTag
=
(
scriptId
:
string
,
doc
:
Document
,
url
:
string
,
callback
:
callbackFn
)
=>
{
const
scriptTag
=
doc
.
createElement
(
'script'
);
scriptTag
.
referrerPolicy
=
'origin'
;
scriptTag
.
type
=
'application/javascript'
;
scriptTag
.
id
=
scriptId
;
scriptTag
.
src
=
url
;
const
handler
=
()
=>
{
scriptTag
.
removeEventListener
(
'load'
,
handler
);
callback
();
};
scriptTag
.
addEventListener
(
'load'
,
handler
);
if
(
doc
.
head
)
{
doc
.
head
.
appendChild
(
scriptTag
);
}
};
const
load
=
(
doc
:
Document
,
url
:
string
,
callback
:
callbackFn
)
=>
{
if
(
state
.
scriptLoaded
)
{
callback
();
}
else
{
state
.
listeners
.
push
(
callback
);
if
(
!
doc
.
getElementById
(
state
.
scriptId
))
{
injectScriptTag
(
state
.
scriptId
,
doc
,
url
,
()
=>
{
state
.
listeners
.
forEach
((
fn
)
=>
fn
());
state
.
scriptLoaded
=
true
;
});
}
}
};
// Only to be used by tests.
const
reinitialize
=
()
=>
{
state
=
createState
();
};
return
{
load
,
reinitialize
};
};
const
ScriptLoader
=
CreateScriptLoader
();
export
{
ScriptLoader
};
\ No newline at end of file
src/components/Tinymce/src/lib/components/Editor.ts
deleted
100644 → 0
浏览文件 @
9c02d8ec
/**
* Copyright (c) 2018-present, Ephox, Inc.
*
* This source code is licensed under the Apache 2 license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options';
// import { CreateElement, Vue } from 'vue/types/vue';
import
{
ScriptLoader
}
from
'../ScriptLoader'
;
import
{
getTinymce
}
from
'../TinyMCE'
;
import
{
initEditor
,
isTextarea
,
mergePlugins
,
uuid
,
isNullOrUndefined
}
from
'../Utils'
;
import
{
editorProps
,
IPropTypes
}
from
'./EditorPropTypes'
;
import
{
h
,
defineComponent
,
ComponentPublicInstance
}
from
'vue'
export
interface
IEditor
{
$props
:
Partial
<
IPropTypes
>
}
declare
module
'@vue/runtime-core'
{
interface
ComponentCustomProperties
{
elementId
:
string
;
element
:
Element
|
null
;
editor
:
any
;
inlineEditor
:
boolean
;
$props
:
Partial
<
IPropTypes
>
;
}
}
const
renderInline
=
(
id
:
string
,
tagName
?:
string
)
=>
{
return
h
(
tagName
?
tagName
:
'div'
,
{
id
});
};
const
renderIframe
=
(
id
:
string
)
=>
{
return
h
(
'textarea'
,
{
id
,
visibility
:
'hidden'
});
};
const
initialise
=
(
ctx
:
ComponentPublicInstance
)
=>
()
=>
{
const
finalInit
=
{
...
ctx
.
$props
.
init
,
readonly
:
ctx
.
$props
.
disabled
,
selector
:
`#
${
ctx
.
elementId
}
`
,
plugins
:
mergePlugins
(
ctx
.
$props
.
init
&&
ctx
.
$props
.
init
.
plugins
,
ctx
.
$props
.
plugins
),
toolbar
:
ctx
.
$props
.
toolbar
||
(
ctx
.
$props
.
init
&&
ctx
.
$props
.
init
.
toolbar
),
inline
:
ctx
.
inlineEditor
,
setup
:
(
editor
:
any
)
=>
{
ctx
.
editor
=
editor
;
editor
.
on
(
'init'
,
(
e
:
Event
)
=>
initEditor
(
e
,
ctx
,
editor
));
if
(
ctx
.
$props
.
init
&&
typeof
ctx
.
$props
.
init
.
setup
===
'function'
)
{
ctx
.
$props
.
init
.
setup
(
editor
);
}
}
};
if
(
isTextarea
(
ctx
.
element
))
{
ctx
.
element
.
style
.
visibility
=
''
;
}
getTinymce
().
init
(
finalInit
);
};
export
const
Editor
=
defineComponent
({
props
:
editorProps
,
created
()
{
this
.
elementId
=
this
.
$props
.
id
||
uuid
(
'tiny-vue'
);
this
.
inlineEditor
=
(
this
.
$props
.
init
&&
this
.
$props
.
init
.
inline
)
||
this
.
$props
.
inline
;
},
watch
:
{
disabled
()
{
(
this
as
any
).
editor
.
setMode
(
this
.
disabled
?
'readonly'
:
'design'
);
}
},
mounted
()
{
this
.
element
=
this
.
$el
;
if
(
getTinymce
()
!==
null
)
{
initialise
(
this
)();
}
else
if
(
this
.
element
&&
this
.
element
.
ownerDocument
)
{
const
channel
=
this
.
$props
.
cloudChannel
?
this
.
$props
.
cloudChannel
:
'5'
;
const
apiKey
=
this
.
$props
.
apiKey
?
this
.
$props
.
apiKey
:
'no-api-key'
;
const
scriptSrc
=
isNullOrUndefined
(
this
.
$props
.
tinymceScriptSrc
)
?
`https://cdn.tiny.cloud/1/
${
apiKey
}
/tinymce/
${
channel
}
/tinymce.min.js`
:
this
.
$props
.
tinymceScriptSrc
;
ScriptLoader
.
load
(
this
.
element
.
ownerDocument
,
scriptSrc
,
initialise
(
this
)
);
}
},
beforeUnmount
()
{
if
(
getTinymce
()
!==
null
)
{
getTinymce
().
remove
(
this
.
editor
);
}
},
render
()
{
return
this
.
inlineEditor
?
renderInline
(
this
.
elementId
,
this
.
$props
.
tagName
)
:
renderIframe
(
this
.
elementId
);
}
})
src/components/Tinymce/src/lib/components/EditorPropTypes.ts
deleted
100644 → 0
浏览文件 @
9c02d8ec
/**
* Copyright (c) 2018-present, Ephox, Inc.
*
* This source code is licensed under the Apache 2 license found in the
* LICENSE file in the root directory of this source tree.
*
*/
export
type
CopyProps
<
T
>
=
{
[
P
in
keyof
T
]:
any
};
export
interface
IPropTypes
{
apiKey
:
string
;
cloudChannel
:
string
;
id
:
string
;
init
:
any
;
initialValue
:
string
;
outputFormat
:
'html'
|
'text'
;
inline
:
boolean
;
modelEvents
:
string
[]
|
string
;
plugins
:
string
[]
|
string
;
tagName
:
string
;
toolbar
:
string
[]
|
string
;
modelValue
:
string
;
disabled
:
boolean
;
tinymceScriptSrc
:
string
;
}
export
const
editorProps
:
CopyProps
<
IPropTypes
>
=
{
apiKey
:
String
,
cloudChannel
:
String
,
id
:
String
,
init
:
Object
,
initialValue
:
String
,
inline
:
Boolean
,
modelEvents
:
[
String
,
Array
],
plugins
:
[
String
,
Array
],
tagName
:
String
,
toolbar
:
[
String
,
Array
],
modelValue
:
String
,
disabled
:
Boolean
,
tinymceScriptSrc
:
String
,
outputFormat
:
{
type
:
String
,
validator
:
(
prop
:
string
)
=>
prop
===
'html'
||
prop
===
'text'
},
};
src/components/Tinymce/src/lib/global.d.ts
deleted
100644 → 0
浏览文件 @
9c02d8ec
// Global compile-time constants
declare
var
__DEV__
:
boolean
declare
var
__BROWSER__
:
boolean
declare
var
__CI__
:
boolean
src/components/Tinymce/src/lib/index.ts
deleted
100644 → 0
浏览文件 @
9c02d8ec
import
{
Editor
}
from
'./components/Editor'
;
export
default
Editor
;
src/components/Tinymce/src/props.ts
浏览文件 @
f75425d1
import
{
PropType
}
from
'vue'
;
import
{
PropType
}
from
'vue'
;
export
const
basicProps
=
{
export
const
basicProps
=
{
id
:
{
type
:
String
as
PropType
<
string
>
,
default
:
()
=>
{
return
`tinymce-
${
new
Date
().
getTime
()}${(
Math
.
random
()
*
1000
).
toFixed
(
0
)}
`
;
},
},
menubar
:
{
menubar
:
{
type
:
String
as
PropType
<
string
>
,
type
:
String
as
PropType
<
string
>
,
default
:
'file edit insert view format table'
,
default
:
'file edit insert view format table'
,
...
@@ -15,6 +9,10 @@ export const basicProps = {
...
@@ -15,6 +9,10 @@ export const basicProps = {
type
:
String
as
PropType
<
string
>
,
type
:
String
as
PropType
<
string
>
,
// default: ''
// default: ''
},
},
modelValue
:
{
type
:
String
as
PropType
<
string
>
,
// default: ''
},
// 高度
// 高度
height
:
{
height
:
{
type
:
[
Number
,
String
]
as
PropType
<
string
|
number
>
,
type
:
[
Number
,
String
]
as
PropType
<
string
|
number
>
,
...
...
src/router/menus/modules/demo/charts.ts
浏览文件 @
f75425d1
...
@@ -6,23 +6,23 @@ const menu: MenuModule = {
...
@@ -6,23 +6,23 @@ const menu: MenuModule = {
path
:
'/charts'
,
path
:
'/charts'
,
children
:
[
children
:
[
{
{
path
:
'
/
apexChart'
,
path
:
'apexChart'
,
name
:
'ApexChart'
,
name
:
'ApexChart'
,
},
},
{
{
path
:
'
/
echarts'
,
path
:
'echarts'
,
name
:
'Echarts'
,
name
:
'Echarts'
,
children
:
[
children
:
[
{
{
path
:
'
/
map'
,
path
:
'map'
,
name
:
'地图'
,
name
:
'地图'
,
},
},
{
{
path
:
'
/
line'
,
path
:
'line'
,
name
:
'折线图'
,
name
:
'折线图'
,
},
},
{
{
path
:
'
/
pie'
,
path
:
'pie'
,
name
:
'饼图'
,
name
:
'饼图'
,
},
},
],
],
...
...
src/router/menus/modules/demo/comp.ts
浏览文件 @
f75425d1
...
@@ -6,16 +6,16 @@ const menu: MenuModule = {
...
@@ -6,16 +6,16 @@ const menu: MenuModule = {
path
:
'/comp'
,
path
:
'/comp'
,
children
:
[
children
:
[
{
{
path
:
'
/
basic'
,
path
:
'basic'
,
name
:
'基础组件'
,
name
:
'基础组件'
,
},
},
{
{
path
:
'
/
countTo'
,
path
:
'countTo'
,
name
:
'数字动画'
,
name
:
'数字动画'
,
},
},
{
{
path
:
'
/
scroll'
,
path
:
'scroll'
,
name
:
'滚动组件'
,
name
:
'滚动组件'
,
children
:
[
children
:
[
{
{
...
@@ -33,53 +33,39 @@ const menu: MenuModule = {
...
@@ -33,53 +33,39 @@ const menu: MenuModule = {
],
],
},
},
{
{
path
:
'
/
modal'
,
path
:
'modal'
,
name
:
'弹窗扩展'
,
name
:
'弹窗扩展'
,
},
},
{
{
path
:
'
/
drawer'
,
path
:
'drawer'
,
name
:
'抽屉扩展'
,
name
:
'抽屉扩展'
,
},
},
{
{
path
:
'
/
desc'
,
path
:
'desc'
,
name
:
'详情组件'
,
name
:
'详情组件'
,
},
},
{
{
path
:
'
/
verify'
,
path
:
'verify'
,
name
:
'验证组件'
,
name
:
'验证组件'
,
children
:
[
children
:
[
{
{
path
:
'
/
drag'
,
path
:
'drag'
,
name
:
'拖拽校验'
,
name
:
'拖拽校验'
,
},
},
{
{
path
:
'
/
rotate'
,
path
:
'rotate'
,
name
:
'图片还原校验'
,
name
:
'图片还原校验'
,
},
},
],
],
},
},
{
{
path
:
'
/
qrcode'
,
path
:
'qrcode'
,
name
:
'二维码组件'
,
name
:
'二维码组件'
,
},
},
{
{
path
:
'
/
strength-meter'
,
path
:
'strength-meter'
,
name
:
'密码强度组件'
,
name
:
'密码强度组件'
,
},
},
{
path
:
'/tinymce'
,
name
:
'富文本'
,
children
:
[
{
path
:
'/index'
,
name
:
'基础使用'
,
},
{
path
:
'/editor'
,
name
:
'嵌入form使用'
,
},
],
},
],
],
},
},
};
};
...
...
src/router/menus/modules/demo/editor.ts
浏览文件 @
f75425d1
...
@@ -6,9 +6,23 @@ const menu: MenuModule = {
...
@@ -6,9 +6,23 @@ const menu: MenuModule = {
path
:
'/editor'
,
path
:
'/editor'
,
children
:
[
children
:
[
{
{
path
:
'
/
markdown'
,
path
:
'markdown'
,
name
:
'markdown编辑器'
,
name
:
'markdown编辑器'
,
},
},
{
path
:
'tinymce'
,
name
:
'富文本'
,
children
:
[
{
path
:
'index'
,
name
:
'基础使用'
,
},
// {
// path: 'editor',
// name: '嵌入form使用',
// },
],
},
],
],
},
},
};
};
...
...
src/router/menus/modules/demo/excel.ts
浏览文件 @
f75425d1
...
@@ -6,23 +6,21 @@ const menu: MenuModule = {
...
@@ -6,23 +6,21 @@ const menu: MenuModule = {
path
:
'/excel'
,
path
:
'/excel'
,
children
:
[
children
:
[
{
{
path
:
'
/
customExport'
,
path
:
'customExport'
,
name
:
'选择导出格式'
,
name
:
'选择导出格式'
,
},
},
{
{
path
:
'
/
jsonExport'
,
path
:
'jsonExport'
,
name
:
'JSON数据导出'
,
name
:
'JSON数据导出'
,
},
},
{
{
path
:
'
/
arrayExport'
,
path
:
'arrayExport'
,
name
:
'Array数据导出'
,
name
:
'Array数据导出'
,
},
},
{
{
path
:
'
/
importExcel'
,
path
:
'importExcel'
,
name
:
'导入'
,
name
:
'导入'
,
},
},
// ],
// },
],
],
},
},
};
};
...
...
src/router/menus/modules/demo/exception.ts
浏览文件 @
f75425d1
...
@@ -6,27 +6,27 @@ const menu: MenuModule = {
...
@@ -6,27 +6,27 @@ const menu: MenuModule = {
path
:
'/exception'
,
path
:
'/exception'
,
children
:
[
children
:
[
{
{
path
:
'
/
404'
,
path
:
'404'
,
name
:
'404'
,
name
:
'404'
,
},
},
{
{
path
:
'
/
500'
,
path
:
'500'
,
name
:
'500'
,
name
:
'500'
,
},
},
{
{
path
:
'
/
net-work-error'
,
path
:
'net-work-error'
,
name
:
'网络错误'
,
name
:
'网络错误'
,
},
},
{
{
path
:
'
/
page-time-out'
,
path
:
'page-time-out'
,
name
:
'页面超时'
,
name
:
'页面超时'
,
},
},
{
{
path
:
'
/
not-data'
,
path
:
'not-data'
,
name
:
'无数据'
,
name
:
'无数据'
,
},
},
{
{
path
:
'
/
error-log'
,
path
:
'error-log'
,
name
:
'错误日志'
,
name
:
'错误日志'
,
},
},
],
],
...
...
src/router/menus/modules/demo/feat.ts
浏览文件 @
f75425d1
...
@@ -6,55 +6,55 @@ const menu: MenuModule = {
...
@@ -6,55 +6,55 @@ const menu: MenuModule = {
path
:
'/feat'
,
path
:
'/feat'
,
children
:
[
children
:
[
{
{
path
:
'
/
icon'
,
path
:
'icon'
,
name
:
'图标'
,
name
:
'图标'
,
},
},
{
{
path
:
'
/
tabs'
,
path
:
'tabs'
,
name
:
'标签页操作'
,
name
:
'标签页操作'
,
},
},
{
{
path
:
'
/
context-menu'
,
path
:
'context-menu'
,
name
:
'右键菜单'
,
name
:
'右键菜单'
,
},
},
{
{
path
:
'
/
click-out-side'
,
path
:
'click-out-side'
,
name
:
'ClickOutSide'
,
name
:
'ClickOutSide'
,
},
},
{
{
path
:
'
/
img-preview'
,
path
:
'img-preview'
,
name
:
'图片预览'
,
name
:
'图片预览'
,
},
},
{
{
path
:
'
/
i18n'
,
path
:
'i18n'
,
name
:
'国际化'
,
name
:
'国际化'
,
},
},
{
{
path
:
'
/
copy'
,
path
:
'copy'
,
name
:
'剪切板'
,
name
:
'剪切板'
,
},
},
{
{
path
:
'
/
msg'
,
path
:
'msg'
,
name
:
'消息提示'
,
name
:
'消息提示'
,
},
},
{
{
path
:
'
/
watermark'
,
path
:
'watermark'
,
name
:
'水印'
,
name
:
'水印'
,
},
},
{
{
path
:
'
/
full-screen'
,
path
:
'full-screen'
,
name
:
'全屏'
,
name
:
'全屏'
,
},
},
{
{
path
:
'
/
testTab'
,
path
:
'testTab'
,
name
:
'带参Tab'
,
name
:
'带参Tab'
,
children
:
[
children
:
[
{
{
path
:
'
/
id1'
,
path
:
'id1'
,
name
:
'带参tab1'
,
name
:
'带参tab1'
,
},
},
{
{
path
:
'
/
id2'
,
path
:
'id2'
,
name
:
'带参tab2'
,
name
:
'带参tab2'
,
},
},
],
],
...
...
src/router/menus/modules/demo/form.ts
浏览文件 @
f75425d1
...
@@ -6,31 +6,31 @@ const menu: MenuModule = {
...
@@ -6,31 +6,31 @@ const menu: MenuModule = {
name
:
'Form'
,
name
:
'Form'
,
children
:
[
children
:
[
{
{
path
:
'
/
basic'
,
path
:
'basic'
,
name
:
'基础表单'
,
name
:
'基础表单'
,
},
},
{
{
path
:
'
/
useForm'
,
path
:
'useForm'
,
name
:
'useForm'
,
name
:
'useForm'
,
},
},
{
{
path
:
'
/
refForm'
,
path
:
'refForm'
,
name
:
'RefForm'
,
name
:
'RefForm'
,
},
},
{
{
path
:
'
/
advancedForm'
,
path
:
'advancedForm'
,
name
:
'可收缩表单'
,
name
:
'可收缩表单'
,
},
},
{
{
path
:
'
/
ruleForm'
,
path
:
'ruleForm'
,
name
:
'表单校验'
,
name
:
'表单校验'
,
},
},
{
{
path
:
'
/
dynamicForm'
,
path
:
'dynamicForm'
,
name
:
'动态表单'
,
name
:
'动态表单'
,
},
},
{
{
path
:
'
/
customerForm'
,
path
:
'customerForm'
,
name
:
'自定义组件'
,
name
:
'自定义组件'
,
},
},
],
],
...
...
src/router/menus/modules/demo/iframe.ts
浏览文件 @
f75425d1
...
@@ -6,15 +6,15 @@ const menu: MenuModule = {
...
@@ -6,15 +6,15 @@ const menu: MenuModule = {
path
:
'/frame'
,
path
:
'/frame'
,
children
:
[
children
:
[
{
{
path
:
'
/
antv'
,
path
:
'antv'
,
name
:
'antVue文档(内嵌)'
,
name
:
'antVue文档(内嵌)'
,
},
},
{
{
path
:
'
/
doc'
,
path
:
'doc'
,
name
:
'项目文档(内嵌)'
,
name
:
'项目文档(内嵌)'
,
},
},
{
{
path
:
'
/
docExternal'
,
path
:
'docExternal'
,
name
:
'项目文档(外链)'
,
name
:
'项目文档(外链)'
,
},
},
],
],
...
...
src/router/menus/modules/demo/permission.ts
浏览文件 @
f75425d1
...
@@ -6,37 +6,37 @@ const menu: MenuModule = {
...
@@ -6,37 +6,37 @@ const menu: MenuModule = {
path
:
'/permission'
,
path
:
'/permission'
,
children
:
[
children
:
[
{
{
path
:
'
/
front'
,
path
:
'front'
,
name
:
'基于前端'
,
name
:
'基于前端'
,
children
:
[
children
:
[
{
{
path
:
'
/
page'
,
path
:
'page'
,
name
:
'页面权限'
,
name
:
'页面权限'
,
},
},
{
{
path
:
'
/
btn'
,
path
:
'btn'
,
name
:
'按钮权限'
,
name
:
'按钮权限'
,
},
},
{
{
path
:
'
/
auth-pageA'
,
path
:
'auth-pageA'
,
name
:
'权限测试页A'
,
name
:
'权限测试页A'
,
},
},
{
{
path
:
'
/
auth-pageB'
,
path
:
'auth-pageB'
,
name
:
'权限测试页B'
,
name
:
'权限测试页B'
,
},
},
],
],
},
},
{
{
path
:
'
/
back'
,
path
:
'back'
,
name
:
'基于后台'
,
name
:
'基于后台'
,
children
:
[
children
:
[
{
{
path
:
'
/
page'
,
path
:
'page'
,
name
:
'页面权限'
,
name
:
'页面权限'
,
},
},
{
{
path
:
'
/
btn'
,
path
:
'btn'
,
name
:
'按钮权限'
,
name
:
'按钮权限'
,
},
},
],
],
...
...
src/router/menus/modules/demo/table.ts
浏览文件 @
f75425d1
...
@@ -6,59 +6,59 @@ const menu: MenuModule = {
...
@@ -6,59 +6,59 @@ const menu: MenuModule = {
name
:
'Table'
,
name
:
'Table'
,
children
:
[
children
:
[
{
{
path
:
'
/
basic'
,
path
:
'basic'
,
name
:
'基础表格'
,
name
:
'基础表格'
,
},
},
{
{
path
:
'
/
treeTable'
,
path
:
'treeTable'
,
name
:
'树形表格'
,
name
:
'树形表格'
,
},
},
{
{
path
:
'
/
fetchTable'
,
path
:
'fetchTable'
,
name
:
'远程加载'
,
name
:
'远程加载'
,
},
},
{
{
path
:
'
/
fixedColumn'
,
path
:
'fixedColumn'
,
name
:
'固定列'
,
name
:
'固定列'
,
},
},
{
{
path
:
'
/
customerCell'
,
path
:
'customerCell'
,
name
:
'自定义列'
,
name
:
'自定义列'
,
},
},
{
{
path
:
'
/
formTable'
,
path
:
'formTable'
,
name
:
'开启搜索区域'
,
name
:
'开启搜索区域'
,
},
},
{
{
path
:
'
/
useTable'
,
path
:
'useTable'
,
name
:
'UseTable'
,
name
:
'UseTable'
,
},
},
{
{
path
:
'
/
refTable'
,
path
:
'refTable'
,
name
:
'RefTable'
,
name
:
'RefTable'
,
},
},
{
{
path
:
'
/
multipleHeader'
,
path
:
'multipleHeader'
,
name
:
'多级表头'
,
name
:
'多级表头'
,
},
},
{
{
path
:
'
/
mergeHeader'
,
path
:
'mergeHeader'
,
name
:
'合并单元格'
,
name
:
'合并单元格'
,
},
},
{
{
path
:
'
/
expandTable'
,
path
:
'expandTable'
,
name
:
'可展开表格'
,
name
:
'可展开表格'
,
},
},
{
{
path
:
'
/
fixedHeight'
,
path
:
'fixedHeight'
,
name
:
'定高/头部自定义'
,
name
:
'定高/头部自定义'
,
},
},
{
{
path
:
'
/
footerTable'
,
path
:
'footerTable'
,
name
:
'表尾行合计'
,
name
:
'表尾行合计'
,
},
},
{
{
path
:
'
/
editCellTable'
,
path
:
'editCellTable'
,
name
:
'可编辑单元格'
,
name
:
'可编辑单元格'
,
},
},
],
],
...
...
src/router/routes/modules/demo/comp.ts
浏览文件 @
f75425d1
...
@@ -136,31 +136,5 @@ export default {
...
@@ -136,31 +136,5 @@ export default {
title
:
'密码强度组件'
,
title
:
'密码强度组件'
,
},
},
},
},
{
path
:
'/tinymce'
,
name
:
'TinymceDemo'
,
meta
:
{
title
:
'富文本'
,
},
redirect
:
'/comp/tinymce/index'
,
children
:
[
{
path
:
'index'
,
name
:
'Tinymce'
,
component
:
()
=>
import
(
'/@/views/demo/comp/tinymce/index.vue'
),
meta
:
{
title
:
'基础使用'
,
},
},
{
path
:
'editor'
,
name
:
'TinymceEditor'
,
component
:
()
=>
import
(
'/@/views/demo/comp/tinymce/Editor.vue'
),
meta
:
{
title
:
'嵌入form使用'
,
},
},
],
},
],
],
}
as
AppRouteModule
;
}
as
AppRouteModule
;
src/router/routes/modules/demo/editor.ts
浏览文件 @
f75425d1
...
@@ -23,5 +23,32 @@ export default {
...
@@ -23,5 +23,32 @@ export default {
title
:
'markdown编辑器'
,
title
:
'markdown编辑器'
,
},
},
},
},
{
path
:
'/tinymce'
,
name
:
'TinymceDemo'
,
meta
:
{
title
:
'富文本'
,
},
redirect
:
'/editor/tinymce/index'
,
children
:
[
{
path
:
'index'
,
name
:
'TinymceBasicDemo'
,
component
:
()
=>
import
(
'/@/views/demo/editor/tinymce/index.vue'
),
meta
:
{
title
:
'基础使用'
,
},
},
// TODO
// {
// path: 'editor',
// name: 'TinymceFormDemo',
// component: () => import('/@/views/demo/comp/tinymce/Editor.vue'),
// meta: {
// title: '嵌入form使用',
// },
// },
],
},
],
],
}
as
AppRouteModule
;
}
as
AppRouteModule
;
src/utils/is.ts
浏览文件 @
f75425d1
...
@@ -67,3 +67,7 @@ export const isServer = typeof window === 'undefined';
...
@@ -67,3 +67,7 @@ export const isServer = typeof window === 'undefined';
export
function
isImageDom
(
o
:
Element
)
{
export
function
isImageDom
(
o
:
Element
)
{
return
o
&&
[
'IMAGE'
,
'IMG'
].
includes
(
o
.
tagName
);
return
o
&&
[
'IMAGE'
,
'IMG'
].
includes
(
o
.
tagName
);
}
}
export
const
isTextarea
=
(
element
:
Element
|
null
):
element
is
HTMLTextAreaElement
=>
{
return
element
!==
null
&&
element
.
tagName
.
toLowerCase
()
===
'textarea'
;
};
src/utils/uuid.ts
浏览文件 @
f75425d1
...
@@ -17,3 +17,11 @@ export function buildUUID(): string {
...
@@ -17,3 +17,11 @@ export function buildUUID(): string {
}
}
return
uuid
.
replace
(
/-/g
,
''
);
return
uuid
.
replace
(
/-/g
,
''
);
}
}
let
unique
=
0
;
export
function
snowUuid
(
prefix
:
string
):
string
{
const
time
=
Date
.
now
();
const
random
=
Math
.
floor
(
Math
.
random
()
*
1000000000
);
unique
++
;
return
prefix
+
'_'
+
random
+
unique
+
String
(
time
);
}
src/views/demo/
comp
/tinymce/Editor.vue
→
src/views/demo/
editor
/tinymce/Editor.vue
浏览文件 @
f75425d1
...
@@ -43,7 +43,7 @@
...
@@ -43,7 +43,7 @@
},
},
];
];
export
default
defineComponent
({
export
default
defineComponent
({
components
:
{
BasicForm
,
CollapseContainer
,
Tinymce
},
components
:
{
BasicForm
,
CollapseContainer
},
setup
()
{
setup
()
{
const
{
createMessage
}
=
useMessage
();
const
{
createMessage
}
=
useMessage
();
...
...
src/views/demo/
comp
/tinymce/index.vue
→
src/views/demo/
editor
/tinymce/index.vue
浏览文件 @
f75425d1
<
template
>
<
template
>
<div
class=
"flex p-4"
>
<div
class=
"flex p-4"
>
<Tinymce
value=
"Hello, World!"
@
change=
"handleChange"
width=
"100%"
/>
{{
value
}}
<Tinymce
v-model=
"value"
@
change=
"handleChange"
width=
"100%"
/>
</div>
</div>
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'vue'
;
import
{
defineComponent
,
ref
}
from
'vue'
;
import
{
Tinymce
}
from
'/@/components/Tinymce/index'
;
import
{
Tinymce
}
from
'/@/components/Tinymce/index'
;
export
default
defineComponent
({
export
default
defineComponent
({
components
:
{
Tinymce
},
components
:
{
Tinymce
},
setup
()
{
setup
()
{
const
value
=
ref
(
'hello world!'
);
function
handleChange
(
value
:
string
)
{
function
handleChange
(
value
:
string
)
{
console
.
log
(
value
);
console
.
log
(
value
);
}
}
return
{
handleChange
};
// setTimeout(() => {
// value.value = '1233';
// }, 5000);
return
{
handleChange
,
value
};
},
},
});
});
</
script
>
</
script
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论