Skip to content

Commit

Permalink
feat: ✨ 添加代码编辑器组件
Browse files Browse the repository at this point in the history
  • Loading branch information
ShanYi-Hui committed May 23, 2024
1 parent 12cffac commit eadadd2
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 55 deletions.
105 changes: 51 additions & 54 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,56 @@ export {}

declare module 'vue' {
export interface GlobalComponents {
ActionButton: typeof import('./src/components/Search/src/components/ActionButton.vue')['default']
Backtop: typeof import('./src/components/Backtop/src/Backtop.vue')['default']
Breadcrumb: typeof import('./src/components/Breadcrumb/src/Breadcrumb.vue')['default']
Button: typeof import('./src/components/Button/src/Button.vue')['default']
Collapse: typeof import('./src/components/Collapse/src/Collapse.vue')['default']
ColorRadioPicker: typeof import('./src/components/Setting/src/components/ColorRadioPicker.vue')['default']
ColumnSetting: typeof import('./src/components/Table/src/components/ColumnSetting.vue')['default']
ConfigGlobal: typeof import('./src/components/ConfigGlobal/src/ConfigGlobal.vue')['default']
ContentDetailWrap: typeof import('./src/components/ContentDetailWrap/src/ContentDetailWrap.vue')['default']
ContentWrap: typeof import('./src/components/ContentWrap/src/ContentWrap.vue')['default']
ContextMenu: typeof import('./src/components/ContextMenu/src/ContextMenu.vue')['default']
CountTo: typeof import('./src/components/CountTo/src/CountTo.vue')['default']
Descriptions: typeof import('./src/components/Descriptions/src/Descriptions.vue')['default']
Dialog: typeof import('./src/components/Dialog/src/Dialog.vue')['default']
Echart: typeof import('./src/components/Echart/src/Echart.vue')['default']
Editor: typeof import('./src/components/Editor/src/Editor.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
Error: typeof import('./src/components/Error/src/Error.vue')['default']
Footer: typeof import('./src/components/Footer/src/Footer.vue')['default']
Form: typeof import('./src/components/Form/src/Form.vue')['default']
Highlight: typeof import('./src/components/Highlight/src/Highlight.vue')['default']
Icon: typeof import('./src/components/Icon/src/Icon.vue')['default']
IconPicker: typeof import('./src/components/IconPicker/src/IconPicker.vue')['default']
ImageCropping: typeof import('./src/components/ImageCropping/src/ImageCropping.vue')['default']
ImageViewer: typeof import('./src/components/ImageViewer/src/ImageViewer.vue')['default']
Infotip: typeof import('./src/components/Infotip/src/Infotip.vue')['default']
InputPassword: typeof import('./src/components/InputPassword/src/InputPassword.vue')['default']
InterfaceDisplay: typeof import('./src/components/Setting/src/components/InterfaceDisplay.vue')['default']
JsonEditor: typeof import('./src/components/JsonEditor/src/JsonEditor.vue')['default']
LayoutRadioPicker: typeof import('./src/components/Setting/src/components/LayoutRadioPicker.vue')['default']
LockDialog: typeof import('./src/components/UserInfo/src/components/LockDialog.vue')['default']
LockPage: typeof import('./src/components/UserInfo/src/components/LockPage.vue')['default']
Logo: typeof import('./src/components/Logo/src/Logo.vue')['default']
Menu: typeof import('./src/components/Menu/src/Menu.vue')['default']
Permission: typeof import('./src/components/Permission/src/Permission.vue')['default']
Qrcode: typeof import('./src/components/Qrcode/src/Qrcode.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Screenfull: typeof import('./src/components/Screenfull/src/Screenfull.vue')['default']
Search: typeof import('./src/components/Search/src/Search.vue')['default']
Setting: typeof import('./src/components/Setting/src/Setting.vue')['default']
SizeDropdown: typeof import('./src/components/SizeDropdown/src/SizeDropdown.vue')['default']
Table: typeof import('./src/components/Table/src/Table.vue')['default']
TableActions: typeof import('./src/components/Table/src/components/TableActions.vue')['default']
TabMenu: typeof import('./src/components/TabMenu/src/TabMenu.vue')['default']
TagsView: typeof import('./src/components/TagsView/src/TagsView.vue')['default']
ThemeSwitch: typeof import('./src/components/ThemeSwitch/src/ThemeSwitch.vue')['default']
UserInfo: typeof import('./src/components/UserInfo/src/UserInfo.vue')['default']
VideoPlayer: typeof import('./src/components/VideoPlayer/src/VideoPlayer.vue')['default']
VideoPlayerViewer: typeof import('./src/components/VideoPlayerViewer/src/VideoPlayerViewer.vue')['default']
Waterfall: typeof import('./src/components/Waterfall/src/Waterfall.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
ActionButton: (typeof import('./src/components/Search/src/components/ActionButton.vue'))['default']
Backtop: (typeof import('./src/components/Backtop/src/Backtop.vue'))['default']
Breadcrumb: (typeof import('./src/components/Breadcrumb/src/Breadcrumb.vue'))['default']
Button: (typeof import('./src/components/Button/src/Button.vue'))['default']
CodeEditor: (typeof import('./src/components/CodeEditor/src/CodeEditor.vue'))['default']
Collapse: (typeof import('./src/components/Collapse/src/Collapse.vue'))['default']
ColorRadioPicker: (typeof import('./src/components/Setting/src/components/ColorRadioPicker.vue'))['default']
ColumnSetting: (typeof import('./src/components/Table/src/components/ColumnSetting.vue'))['default']
ConfigGlobal: (typeof import('./src/components/ConfigGlobal/src/ConfigGlobal.vue'))['default']
ContentDetailWrap: (typeof import('./src/components/ContentDetailWrap/src/ContentDetailWrap.vue'))['default']
ContentWrap: (typeof import('./src/components/ContentWrap/src/ContentWrap.vue'))['default']
ContextMenu: (typeof import('./src/components/ContextMenu/src/ContextMenu.vue'))['default']
CountTo: (typeof import('./src/components/CountTo/src/CountTo.vue'))['default']
Descriptions: (typeof import('./src/components/Descriptions/src/Descriptions.vue'))['default']
Dialog: (typeof import('./src/components/Dialog/src/Dialog.vue'))['default']
Echart: (typeof import('./src/components/Echart/src/Echart.vue'))['default']
Editor: (typeof import('./src/components/Editor/src/Editor.vue'))['default']
Error: (typeof import('./src/components/Error/src/Error.vue'))['default']
Footer: (typeof import('./src/components/Footer/src/Footer.vue'))['default']
Form: (typeof import('./src/components/Form/src/Form.vue'))['default']
Highlight: (typeof import('./src/components/Highlight/src/Highlight.vue'))['default']
Icon: (typeof import('./src/components/Icon/src/Icon.vue'))['default']
IconPicker: (typeof import('./src/components/IconPicker/src/IconPicker.vue'))['default']
ImageCropping: (typeof import('./src/components/ImageCropping/src/ImageCropping.vue'))['default']
ImageViewer: (typeof import('./src/components/ImageViewer/src/ImageViewer.vue'))['default']
Infotip: (typeof import('./src/components/Infotip/src/Infotip.vue'))['default']
InputPassword: (typeof import('./src/components/InputPassword/src/InputPassword.vue'))['default']
InterfaceDisplay: (typeof import('./src/components/Setting/src/components/InterfaceDisplay.vue'))['default']
JsonEditor: (typeof import('./src/components/JsonEditor/src/JsonEditor.vue'))['default']
LayoutRadioPicker: (typeof import('./src/components/Setting/src/components/LayoutRadioPicker.vue'))['default']
LockDialog: (typeof import('./src/components/UserInfo/src/components/LockDialog.vue'))['default']
LockPage: (typeof import('./src/components/UserInfo/src/components/LockPage.vue'))['default']
Logo: (typeof import('./src/components/Logo/src/Logo.vue'))['default']
Menu: (typeof import('./src/components/Menu/src/Menu.vue'))['default']
Permission: (typeof import('./src/components/Permission/src/Permission.vue'))['default']
Qrcode: (typeof import('./src/components/Qrcode/src/Qrcode.vue'))['default']
RouterLink: (typeof import('vue-router'))['RouterLink']
RouterView: (typeof import('vue-router'))['RouterView']
Screenfull: (typeof import('./src/components/Screenfull/src/Screenfull.vue'))['default']
Search: (typeof import('./src/components/Search/src/Search.vue'))['default']
Setting: (typeof import('./src/components/Setting/src/Setting.vue'))['default']
SizeDropdown: (typeof import('./src/components/SizeDropdown/src/SizeDropdown.vue'))['default']
Table: (typeof import('./src/components/Table/src/Table.vue'))['default']
TableActions: (typeof import('./src/components/Table/src/components/TableActions.vue'))['default']
TabMenu: (typeof import('./src/components/TabMenu/src/TabMenu.vue'))['default']
TagsView: (typeof import('./src/components/TagsView/src/TagsView.vue'))['default']
ThemeSwitch: (typeof import('./src/components/ThemeSwitch/src/ThemeSwitch.vue'))['default']
UserInfo: (typeof import('./src/components/UserInfo/src/UserInfo.vue'))['default']
VideoPlayer: (typeof import('./src/components/VideoPlayer/src/VideoPlayer.vue'))['default']
VideoPlayerViewer: (typeof import('./src/components/VideoPlayerViewer/src/VideoPlayerViewer.vue'))['default']
Waterfall: (typeof import('./src/components/Waterfall/src/Waterfall.vue'))['default']
}
}
8 changes: 8 additions & 0 deletions mock/role/index.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ const adminList = [
meta: {
title: 'JSON编辑器'
}
},
{
path: 'code-editor',
component: 'views/Components/Editor/CodeEditor',
name: 'CodeEditor',
meta: {
title: '代码编辑器'
}
}
]
},
Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"vue-json-pretty": "^2.4.0",
"vue-router": "^4.3.0",
"vue-types": "^5.1.1",
"xgplayer": "^3.0.14"
"xgplayer": "^3.0.14",
"monaco-editor": "^0.48.0"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
Expand Down
3 changes: 3 additions & 0 deletions src/components/CodeEditor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import CodeEditor from './src/CodeEditor.vue'

export { CodeEditor }
119 changes: 119 additions & 0 deletions src/components/CodeEditor/src/CodeEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<script setup lang="tsx">
import { useMonacoEditor } from '@/hooks/web/useMonacoEditor'
import { onMounted, computed, watch, ref } from 'vue'
import { ElSelect, ElOption, ElFormItem, ElForm } from 'element-plus'
import { languageOptions, themeOptions } from './config/config'
const props = withDefaults(
defineProps<{
width?: string | number
height?: string | number
languageSelector?: boolean
language?: string
themeSelector?: boolean
theme?: string
editorOption?: Object
modelValue: string
}>(),
{
width: '100%',
height: '100%',
languageSelector: true,
language: 'javascript',
themeSelector: true,
theme: 'vs-dark',
editorOption: () => ({}),
modelValue: ''
}
)
const emits = defineEmits<{
(e: 'blur'): void
(e: 'update:modelValue', val: string): void
}>()
const monacoEditorStyle = computed(() => {
return {
width: typeof props.width === 'string' ? props.width : props.width + 'px',
height: typeof props.height === 'string' ? props.height : props.height + 'px'
}
})
const {
monacoEditorRef,
createEditor,
updateVal,
updateOptions,
getEditor,
changeLanguage,
changeTheme
} = useMonacoEditor(props.language)
onMounted(() => {
const monacoEditor = createEditor(props.editorOption)
updateMonacoVal(props.modelValue)
monacoEditor?.onDidChangeModelContent(() => {
emits('update:modelValue', monacoEditor!.getValue())
})
monacoEditor?.onDidBlurEditorText(() => {
emits('blur')
})
})
watch(
() => props.modelValue,
() => {
updateMonacoVal(props.modelValue)
}
)
const localLanguage = ref(props.language)
watch(localLanguage, (newLanguage) => {
changeLanguage(newLanguage)
})
const localTheme = ref(props.theme)
watch(localTheme, (newTheme) => {
changeTheme(newTheme)
})
function updateMonacoVal(val: string) {
if (val !== getEditor()?.getValue()) {
updateVal(val)
}
}
defineExpose({ updateOptions })
</script>

<template>
<ElForm :inline="true">
<ElFormItem v-if="languageSelector" label="language" class="w-30% mb-5px!">
<ElSelect
v-model="localLanguage"
placeholder="Please select language"
size="small"
filterable
>
<ElOption
v-for="item in languageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem v-if="themeSelector" label="theme" class="w-30% mb-5px!">
<ElSelect v-model="localTheme" placeholder="Please select language" size="small" filterable>
<ElOption
v-for="item in themeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
</ElForm>
<div ref="monacoEditorRef" :style="monacoEditorStyle"></div>
</template>
Loading

0 comments on commit eadadd2

Please sign in to comment.