@robot-admin/naive-ui-components 0.6.28 → 0.6.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -48
- package/README.md +277 -277
- package/dist/C_ActionBar-DYG0Yf3A.css.map +1 -0
- package/dist/C_ActionBar-MAjRhqcI.css.map +1 -0
- package/dist/C_ActionBar.css +47 -47
- package/dist/C_ActionBar.js.map +1 -1
- package/dist/C_ActionBar2.js +1 -1
- package/dist/C_ActionBar2.js.map +1 -1
- package/dist/{C_AntV-A3NXx_sF.css.map → C_AntV-BY8jqqmi.css.map} +1 -1
- package/dist/{C_AntV-D2Zp2qQF.css.map → C_AntV-BbkHc-_a.css.map} +1 -1
- package/dist/C_AntV.css +78 -78
- package/dist/C_AntV.js.map +1 -1
- package/dist/C_AntV2.js +2 -2
- package/dist/C_AntV2.js.map +1 -1
- package/dist/{C_AudioPlayer-CXl4yP_m.css.map → C_AudioPlayer-DKRIGhi7.css.map} +1 -1
- package/dist/{C_AudioPlayer-CcBtt71m.css.map → C_AudioPlayer-DlB6eNsa.css.map} +1 -1
- package/dist/C_AudioPlayer.css +47 -47
- package/dist/C_AudioPlayer.js.map +1 -1
- package/dist/C_AudioPlayer2.js +1 -1
- package/dist/C_AudioPlayer2.js.map +1 -1
- package/dist/{C_AvatarGroup-CtPhfH9h.css.map → C_AvatarGroup-D02zci-i.css.map} +1 -1
- package/dist/{C_AvatarGroup-M1dNPH3E.css.map → C_AvatarGroup-DatHaUlY.css.map} +1 -1
- package/dist/C_AvatarGroup.css +21 -21
- package/dist/C_AvatarGroup.js.map +1 -1
- package/dist/C_AvatarGroup2.js +1 -1
- package/dist/C_AvatarGroup2.js.map +1 -1
- package/dist/{C_Barcode-DjTmDkbQ.css.map → C_Barcode-DYDRDe2O.css.map} +1 -1
- package/dist/{C_Barcode-Do1Ozsmh.css.map → C_Barcode-muJdc_O4.css.map} +1 -1
- package/dist/C_Barcode.css +7 -7
- package/dist/C_Barcode.js.map +1 -1
- package/dist/C_Barcode2.js +1 -1
- package/dist/C_Barcode2.js.map +1 -1
- package/dist/C_Breadcrumb.js.map +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/{C_Captcha-CZmAETly.css.map → C_Captcha-9_hk6VmY.css.map} +1 -1
- package/dist/{C_Captcha-Ccq3DMrR.css.map → C_Captcha-MtASlJ0f.css.map} +1 -1
- package/dist/C_Captcha.css +19 -19
- package/dist/C_Captcha.js.map +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Captcha2.js.map +1 -1
- package/dist/{C_Chat-CcdWgVE8.css.map → C_Chat-CcjZdAwu.css.map} +1 -1
- package/dist/{C_Chat-Cx0woEEe.css.map → C_Chat-Diq7tyWU.css.map} +1 -1
- package/dist/C_Chat.css +65 -65
- package/dist/C_Chat.js.map +1 -1
- package/dist/C_Chat2.js +1 -1
- package/dist/C_Chat2.js.map +1 -1
- package/dist/{C_City-Cv5BESaN.css.map → C_City-Bam08Qv3.css.map} +1 -1
- package/dist/{C_City-DNKv4MpH.css.map → C_City-Bb3W-KaN.css.map} +1 -1
- package/dist/C_City.css +29 -29
- package/dist/C_City.js.map +1 -1
- package/dist/C_City2.js +1 -1
- package/dist/C_City2.js.map +1 -1
- package/dist/C_Code-BFi5xxnM.css.map +1 -0
- package/dist/C_Code-CZ7yfnri.css.map +1 -0
- package/dist/C_Code.css +3 -3
- package/dist/C_Code.js.map +1 -1
- package/dist/C_Code2.js +1 -1
- package/dist/C_Code2.js.map +1 -1
- package/dist/{C_ContextMenu-CCsCeI39.css.map → C_ContextMenu-B3Cgz_wJ.css.map} +1 -1
- package/dist/{C_ContextMenu-DOTBeltf.css.map → C_ContextMenu-u1LixF3_.css.map} +1 -1
- package/dist/C_ContextMenu.css +17 -17
- package/dist/C_ContextMenu.js.map +1 -1
- package/dist/C_ContextMenu2.js +1 -1
- package/dist/C_ContextMenu2.js.map +1 -1
- package/dist/{C_Cron-C0-8b5af.css.map → C_Cron-Civir5-I.css.map} +1 -1
- package/dist/{C_Cron-DqHQ92LN.css.map → C_Cron-iw3qpMsy.css.map} +1 -1
- package/dist/C_Cron.css +37 -37
- package/dist/C_Cron.js.map +1 -1
- package/dist/C_Cron2.js +1 -1
- package/dist/C_Cron2.js.map +1 -1
- package/dist/C_Date.js.map +1 -1
- package/dist/C_Date2.js.map +1 -1
- package/dist/{C_Draggable-Bq6o0qXn.css.map → C_Draggable-BCjIvIwT.css.map} +1 -1
- package/dist/{C_Draggable-r6nhx3yM.css.map → C_Draggable-DwkSlCOS.css.map} +1 -1
- package/dist/C_Draggable.css +46 -46
- package/dist/C_Draggable.js.map +1 -1
- package/dist/C_Draggable2.js +1 -1
- package/dist/C_Draggable2.js.map +1 -1
- package/dist/{C_FilePreview-BVarVvnD.css.map → C_FilePreview-BhcbiXsV.css.map} +1 -1
- package/dist/{C_FilePreview-DHGlV4OR.css.map → C_FilePreview-DJudcIbW.css.map} +1 -1
- package/dist/C_FilePreview.css +91 -91
- package/dist/C_FilePreview.js.map +1 -1
- package/dist/C_FilePreview2.js +1 -1
- package/dist/C_FilePreview2.js.map +1 -1
- package/dist/{C_Form-BciQUPpS.css.map → C_Form-BtcAPIRi.css.map} +1 -1
- package/dist/{C_Form-CKHvXL3O.css.map → C_Form-D_gwQ7hC.css.map} +1 -1
- package/dist/C_Form.css +222 -222
- package/dist/C_Form.js.map +1 -1
- package/dist/C_Form2.js +1 -1
- package/dist/C_Form2.js.map +1 -1
- package/dist/{C_FormSearch-Bmd2CmG6.css.map → C_FormSearch-Bi4XYjjk.css.map} +1 -1
- package/dist/{C_FormSearch-DBNtnjaL.css.map → C_FormSearch-DUGOoX0u.css.map} +1 -1
- package/dist/C_FormSearch.css +45 -45
- package/dist/C_FormSearch.js.map +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormSearch2.js.map +1 -1
- package/dist/{C_FormulaEditor-3WG2vtQl.css.map → C_FormulaEditor-CJk3SSUJ.css.map} +1 -1
- package/dist/{C_FormulaEditor-Cm0CokN5.css.map → C_FormulaEditor-Cy7mjfVO.css.map} +1 -1
- package/dist/C_FormulaEditor.css +78 -78
- package/dist/C_FormulaEditor.js.map +1 -1
- package/dist/C_FormulaEditor2.js +1 -1
- package/dist/C_FormulaEditor2.js.map +1 -1
- package/dist/C_FullCalendar-BQA0OjGB.css.map +1 -0
- package/dist/C_FullCalendar-ChJUosAi.css.map +1 -0
- package/dist/C_FullCalendar.css +3 -3
- package/dist/C_FullCalendar.js.map +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_FullCalendar2.js.map +1 -1
- package/dist/{C_GlobalSearch-B6wK3m3k.css.map → C_GlobalSearch-BNtNpLLD.css.map} +1 -1
- package/dist/{C_GlobalSearch-DoPjldFm.css.map → C_GlobalSearch-BlMeQ2D9.css.map} +1 -1
- package/dist/C_GlobalSearch.css +112 -112
- package/dist/C_GlobalSearch.js.map +1 -1
- package/dist/C_GlobalSearch2.js +1 -1
- package/dist/C_GlobalSearch2.js.map +1 -1
- package/dist/C_Icon.js.map +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/{C_ImageCropper-D3L2-J_J.css.map → C_ImageCropper-BqZpkZfU.css.map} +1 -1
- package/dist/{C_ImageCropper-DrmUlaLi.css.map → C_ImageCropper-CylwGuzS.css.map} +1 -1
- package/dist/C_ImageCropper.css +10 -10
- package/dist/C_ImageCropper.js.map +1 -1
- package/dist/C_ImageCropper2.js +1 -1
- package/dist/C_ImageCropper2.js.map +1 -1
- package/dist/C_Language.js.map +1 -1
- package/dist/C_Language2.js.map +1 -1
- package/dist/{C_Login-Cst_W1XC.css.map → C_Login-BkdnkBKX.css.map} +1 -1
- package/dist/{C_Login-DWZ_6K1x.css.map → C_Login-VkMM6OJ2.css.map} +1 -1
- package/dist/C_Login.css +72 -72
- package/dist/C_Login.js.map +1 -1
- package/dist/C_Login2.js +1 -1
- package/dist/C_Login2.js.map +1 -1
- package/dist/{C_Map-BCJmDnJT.css.map → C_Map-DNnBcY70.css.map} +1 -1
- package/dist/{C_Map-WUMXSAfy.css.map → C_Map-LEXIx6zM.css.map} +1 -1
- package/dist/C_Map.css +4 -4
- package/dist/C_Map.js.map +1 -1
- package/dist/C_Map2.js +1 -1
- package/dist/C_Map2.js.map +1 -1
- package/dist/{C_Markdown-7iBnLDtL.css.map → C_Markdown-Kujzx1qG.css.map} +1 -1
- package/dist/{C_Markdown-BbTvdFCl.css.map → C_Markdown-YCAmBbNF.css.map} +1 -1
- package/dist/C_Markdown.css +33 -33
- package/dist/C_Markdown.js.map +1 -1
- package/dist/C_Markdown2.js +1 -1
- package/dist/C_Markdown2.js.map +1 -1
- package/dist/{C_QRCode-DMxSyogU.css.map → C_QRCode-CFNTda_1.css.map} +1 -1
- package/dist/{C_QRCode-G7fiAkm4.css.map → C_QRCode-CmWr9lK-.css.map} +1 -1
- package/dist/C_QRCode.css +9 -9
- package/dist/C_QRCode.js.map +1 -1
- package/dist/C_QRCode2.js +1 -1
- package/dist/C_QRCode2.js.map +1 -1
- package/dist/{C_Signature-BJMvVPWT.css.map → C_Signature-BDx4ctsE.css.map} +1 -1
- package/dist/{C_Signature-BJUHx2BF.css.map → C_Signature-Bz_uNbwv.css.map} +1 -1
- package/dist/C_Signature.css +15 -15
- package/dist/C_Signature.js.map +1 -1
- package/dist/C_Signature2.js +1 -1
- package/dist/C_Signature2.js.map +1 -1
- package/dist/{C_SplitPane-Br2eK8IG.css.map → C_SplitPane-BOwr1C7K.css.map} +1 -1
- package/dist/{C_SplitPane-DuyzUhKB.css.map → C_SplitPane-N-a_D-7F.css.map} +1 -1
- package/dist/C_SplitPane.css +31 -31
- package/dist/C_SplitPane.js.map +1 -1
- package/dist/C_SplitPane2.js +1 -1
- package/dist/C_SplitPane2.js.map +1 -1
- package/dist/C_Steps-Bk1krgiR.css.map +1 -0
- package/dist/C_Steps-Dn2CMpy1.css.map +1 -0
- package/dist/C_Steps.css +38 -38
- package/dist/C_Steps.js.map +1 -1
- package/dist/C_Steps2.js +1 -1
- package/dist/C_Steps2.js.map +1 -1
- package/dist/{C_Table-vZlcgH6x.css.map → C_Table-BV1wUw6f.css.map} +1 -1
- package/dist/{C_Table-wzAO43l0.css.map → C_Table-LlJ-JEdm.css.map} +1 -1
- package/dist/C_Table.css +93 -93
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +1 -1
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-BsutyC3U.css.map → C_TagsView-JIkRrAHT.css.map} +1 -1
- package/dist/{C_TagsView-Crm7yWg9.css.map → C_TagsView-mrh0FN4H.css.map} +1 -1
- package/dist/C_TagsView.css +36 -36
- package/dist/C_TagsView.js.map +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_TagsView2.js.map +1 -1
- package/dist/C_Time-BzyQVvTS.css.map +1 -0
- package/dist/C_Time-DmpKLQHc.css.map +1 -0
- package/dist/C_Time.css +5 -5
- package/dist/C_Time.js.map +1 -1
- package/dist/C_Time2.js +1 -1
- package/dist/C_Time2.js.map +1 -1
- package/dist/C_Timeline.js.map +1 -1
- package/dist/C_Timeline2.js.map +1 -1
- package/dist/{C_Transfer-CCEqnC-v.css.map → C_Transfer-BOB6OBqS.css.map} +1 -1
- package/dist/{C_Transfer-CStPm4NP.css.map → C_Transfer-Dpq7ezWC.css.map} +1 -1
- package/dist/C_Transfer.css +31 -31
- package/dist/C_Transfer.js.map +1 -1
- package/dist/C_Transfer2.js +1 -1
- package/dist/C_Transfer2.js.map +1 -1
- package/dist/{C_Tree-B-Le4hjQ.css.map → C_Tree-D98nX9qT.css.map} +1 -1
- package/dist/{C_Tree-DnGc_MPb.css.map → C_Tree-ulfm7b-P.css.map} +1 -1
- package/dist/C_Tree.css +33 -33
- package/dist/C_Tree.js.map +1 -1
- package/dist/C_Tree2.js +1 -1
- package/dist/C_Tree2.js.map +1 -1
- package/dist/{C_VideoPlayer-Cdgv4Zq0.css.map → C_VideoPlayer-4J96tKfK.css.map} +1 -1
- package/dist/{C_VideoPlayer-rm0MODUv.css.map → C_VideoPlayer-D35seHkm.css.map} +1 -1
- package/dist/C_VideoPlayer.css +13 -13
- package/dist/C_VideoPlayer.js.map +1 -1
- package/dist/C_VideoPlayer2.js +1 -1
- package/dist/C_VideoPlayer2.js.map +1 -1
- package/dist/{C_VtableGantt-BpY-Rng3.css.map → C_VtableGantt-C2lxFmWg.css.map} +1 -1
- package/dist/{C_VtableGantt-DB87-jdS.css.map → C_VtableGantt-Dwnkw_WL.css.map} +1 -1
- package/dist/C_VtableGantt.css +15 -15
- package/dist/C_VtableGantt.js.map +1 -1
- package/dist/C_VtableGantt2.js +1 -1
- package/dist/C_VtableGantt2.js.map +1 -1
- package/dist/{C_WorkFlow-7F6op6qN.css.map → C_WorkFlow-2hJfvvTK.css.map} +1 -1
- package/dist/{C_WorkFlow-Cy3HWA6A.css.map → C_WorkFlow-DHoNjl8-.css.map} +1 -1
- package/dist/C_WorkFlow.css +108 -108
- package/dist/C_WorkFlow.js.map +1 -1
- package/dist/C_WorkFlow2.js +1 -1
- package/dist/C_WorkFlow2.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants2.d.ts +2 -2
- package/dist/constants3.d.ts +2 -2
- package/dist/constants4.d.ts +3 -3
- package/dist/constants5.d.ts +2 -2
- package/dist/data.d.ts +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index10.vue.d.ts +3 -3
- package/dist/index11.vue.d.ts +4 -4
- package/dist/index13.vue.d.ts +2 -2
- package/dist/index15.vue.d.ts +3 -3
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index18.vue.d.ts +4 -4
- package/dist/index2.vue.d.ts +2 -2
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.ts +1 -1
- package/dist/index22.vue.d.ts +1 -1
- package/dist/index24.vue.d.ts +2 -2
- package/dist/index26.vue.d.ts +3 -3
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.ts +6 -6
- package/dist/index8.vue.d.ts +2 -2
- package/dist/menuAdapter.js.map +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +1547 -1547
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.ts +3 -3
- package/dist/useCropperCore.d.ts +5 -5
- package/dist/useDraggableLayout.d.ts +9 -9
- package/dist/useDynamicFormState.d.ts +2 -2
- package/dist/useEdgeInteraction.d.ts +1 -1
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.ts +1 -1
- package/dist/useQRCode.d.ts +3 -3
- package/dist/useSignatureHistory.d.ts +1 -1
- package/dist/useSplitResize.d.ts +5 -5
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +1 -1
- package/package.json +1 -1
- package/dist/C_ActionBar-jZPsiXtT.css.map +0 -1
- package/dist/C_ActionBar-nnfbZCea.css.map +0 -1
- package/dist/C_Code-DPZlNSxL.css.map +0 -1
- package/dist/C_Code-avZjAnHD.css.map +0 -1
- package/dist/C_FullCalendar-1U4VlG7X.css.map +0 -1
- package/dist/C_FullCalendar-DLUdCtqf.css.map +0 -1
- package/dist/C_Steps-BHYNJI1l.css.map +0 -1
- package/dist/C_Steps-DY7vl-4I.css.map +0 -1
- package/dist/C_Time-Bd_e1YDN.css.map +0 -1
- package/dist/C_Time-CKb_fwdm.css.map +0 -1
package/dist/C_Map.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Map.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_Map.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}
|
package/dist/C_Map2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./export-helper.js";import{NSpin as t}from"naive-ui";import{createCommentVNode as n,createElementBlock as r,createElementVNode as i,createVNode as a,defineComponent as o,nextTick as s,normalizeStyle as c,onMounted as l,onUnmounted as u,openBlock as d,ref as f,unref as p,watch as m}from"vue";import h from"leaflet";import"leaflet/dist/leaflet.css";const g=[{label:`OpenStreetMap`,value:`osm`},{label:`高德地图`,value:`amap`}],_={height:`400px`,center:[39.9042,116.4074],zoom:10,mapType:`osm`},v={url:`https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`,attribution:`© OpenStreetMap contributors`,maxZoom:19,minZoom:1,tileSize:256,detectRetina:!0},y={apiUrl:`https://webapi.amap.com/maps?v=2.0&key=`,note:`高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/`},b={iconRetinaUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png`,iconUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png`,shadowUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png`},x={class:`c-map`},S={key:0,class:`map-loading`};var C=e(o({name:`C_Map`,__name:`index`,props:{height:{default:`400px`},center:{default:()=>[39.9042,116.4074]},zoom:{default:10},markers:{default:()=>[]},mapType:{default:`osm`},amapKey:{default:``}},emits:[`ready`,`markerClick`],setup(e,{emit:o}){delete h.Icon.Default.prototype._getIconUrl,h.Icon.Default.mergeOptions(b);let g=e,_=o,C=f(),w=f(!0),T=null,E=async()=>{if(C.value)try{C.value.innerHTML=``,T=h.map(C.value,{center:g.center,zoom:g.zoom,zoomControl:!0,preferCanvas:!0}),h.tileLayer(v.url,v).addTo(T),O(),await s(),requestAnimationFrame(()=>{T?.invalidateSize({reset:!0,pan:!1})}),w.value=!1,_(`ready`,T)}catch(e){console.error(`OpenStreetMap初始化失败:`,e),w.value=!1}},D=async()=>{if(!(!C.value||!g.amapKey))try{C.value.innerHTML=``;let e=document.createElement(`script`);e.type=`text/javascript`,e.src=`${y.apiUrl}${g.amapKey}`,e.onload=()=>{if(window.AMap){let e=new window.AMap.Map(C.value,{zoom:g.zoom,center:g.center});k(e),w.value=!1,_(`ready`,e)}},e.onerror=()=>{w.value=!1},document.head.appendChild(e)}catch{w.value=!1}},O=()=>{!T||g.mapType!==`osm`||!g.markers||(T.eachLayer(e=>{e instanceof h.Marker&&T.removeLayer(e)}),g.markers.forEach(e=>{let t=h.marker([e.lat,e.lng]);e.popup&&(t.bindPopup(e.popup),t.on(`click`,t=>{_(`markerClick`,e,t)})),t.addTo(T)}))},k=e=>{!e||g.mapType!==`amap`||!g.markers||g.markers.forEach(t=>{let n=new window.AMap.Marker({position:[t.lat,t.lng],title:t.popup||``});if(t.popup){let r=new window.AMap.InfoWindow({content:t.popup,offset:new window.AMap.Pixel(0,-30)});n.on(`click`,()=>{r.open(e,n.getPosition()),_(`markerClick`,t,null)})}n.setMap(e)})};return m(()=>g.markers,()=>{T&&g.mapType===`osm`&&O()},{deep:!0}),m(()=>g.mapType,async(e,t)=>{e!==t&&T&&(T.remove(),T=null,w.value=!0,await s(),e===`amap`&&g.amapKey?await D():await E())}),m([()=>g.center,()=>g.zoom],()=>{T&&T.setView(g.center,g.zoom)},{deep:!0}),l(async()=>{await s(),g.mapType===`amap`&&g.amapKey?await D():await E()}),u(()=>{T&&=(T.remove(),null)}),(e,o)=>(d(),r(`div`,x,[i(`div`,{ref_key:`mapContainer`,ref:C,class:`map-container`,style:c({height:e.height})},null,4),w.value?(d(),r(`div`,S,[a(p(t),{size:`large`})])):n(`v-if`,!0)]))}}),[[`__scopeId`,`data-v-
|
|
1
|
+
import{t as e}from"./export-helper.js";import{NSpin as t}from"naive-ui";import{createCommentVNode as n,createElementBlock as r,createElementVNode as i,createVNode as a,defineComponent as o,nextTick as s,normalizeStyle as c,onMounted as l,onUnmounted as u,openBlock as d,ref as f,unref as p,watch as m}from"vue";import h from"leaflet";import"leaflet/dist/leaflet.css";const g=[{label:`OpenStreetMap`,value:`osm`},{label:`高德地图`,value:`amap`}],_={height:`400px`,center:[39.9042,116.4074],zoom:10,mapType:`osm`},v={url:`https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`,attribution:`© OpenStreetMap contributors`,maxZoom:19,minZoom:1,tileSize:256,detectRetina:!0},y={apiUrl:`https://webapi.amap.com/maps?v=2.0&key=`,note:`高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/`},b={iconRetinaUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png`,iconUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png`,shadowUrl:`https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png`},x={class:`c-map`},S={key:0,class:`map-loading`};var C=e(o({name:`C_Map`,__name:`index`,props:{height:{default:`400px`},center:{default:()=>[39.9042,116.4074]},zoom:{default:10},markers:{default:()=>[]},mapType:{default:`osm`},amapKey:{default:``}},emits:[`ready`,`markerClick`],setup(e,{emit:o}){delete h.Icon.Default.prototype._getIconUrl,h.Icon.Default.mergeOptions(b);let g=e,_=o,C=f(),w=f(!0),T=null,E=async()=>{if(C.value)try{C.value.innerHTML=``,T=h.map(C.value,{center:g.center,zoom:g.zoom,zoomControl:!0,preferCanvas:!0}),h.tileLayer(v.url,v).addTo(T),O(),await s(),requestAnimationFrame(()=>{T?.invalidateSize({reset:!0,pan:!1})}),w.value=!1,_(`ready`,T)}catch(e){console.error(`OpenStreetMap初始化失败:`,e),w.value=!1}},D=async()=>{if(!(!C.value||!g.amapKey))try{C.value.innerHTML=``;let e=document.createElement(`script`);e.type=`text/javascript`,e.src=`${y.apiUrl}${g.amapKey}`,e.onload=()=>{if(window.AMap){let e=new window.AMap.Map(C.value,{zoom:g.zoom,center:g.center});k(e),w.value=!1,_(`ready`,e)}},e.onerror=()=>{w.value=!1},document.head.appendChild(e)}catch{w.value=!1}},O=()=>{!T||g.mapType!==`osm`||!g.markers||(T.eachLayer(e=>{e instanceof h.Marker&&T.removeLayer(e)}),g.markers.forEach(e=>{let t=h.marker([e.lat,e.lng]);e.popup&&(t.bindPopup(e.popup),t.on(`click`,t=>{_(`markerClick`,e,t)})),t.addTo(T)}))},k=e=>{!e||g.mapType!==`amap`||!g.markers||g.markers.forEach(t=>{let n=new window.AMap.Marker({position:[t.lat,t.lng],title:t.popup||``});if(t.popup){let r=new window.AMap.InfoWindow({content:t.popup,offset:new window.AMap.Pixel(0,-30)});n.on(`click`,()=>{r.open(e,n.getPosition()),_(`markerClick`,t,null)})}n.setMap(e)})};return m(()=>g.markers,()=>{T&&g.mapType===`osm`&&O()},{deep:!0}),m(()=>g.mapType,async(e,t)=>{e!==t&&T&&(T.remove(),T=null,w.value=!0,await s(),e===`amap`&&g.amapKey?await D():await E())}),m([()=>g.center,()=>g.zoom],()=>{T&&T.setView(g.center,g.zoom)},{deep:!0}),l(async()=>{await s(),g.mapType===`amap`&&g.amapKey?await D():await E()}),u(()=>{T&&=(T.remove(),null)}),(e,o)=>(d(),r(`div`,x,[i(`div`,{ref_key:`mapContainer`,ref:C,class:`map-container`,style:c({height:e.height})},null,4),w.value?(d(),r(`div`,S,[a(p(t),{size:`large`})])):n(`v-if`,!0)]))}}),[[`__scopeId`,`data-v-340816cd`]]);export{v as i,_ as n,g as r,C as t};
|
|
2
2
|
//# sourceMappingURL=C_Map2.js.map
|
package/dist/C_Map2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Map2.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_Map2.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown-
|
|
1
|
+
{"version":3,"file":"C_Markdown-Kujzx1qG.css","names":[],"sources":["../src/components/C_Markdown/index.vue?vue&type=style&index=0&scoped=b64c492a&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */\n.c-markdown-wrapper[data-v-b64c492a] {\n position: relative;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {\n border-radius: 6px;\n border: 1px solid var(--c-border);\n background-color: var(--c-bg-card);\n /* 禁用状态样式 */\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {\n border-color: var(--c-primary);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {\n border-color: var(--c-primary);\n box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {\n background-color: var(--c-bg-disabled, #fafafc);\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {\n background-color: var(--c-bg-card);\n border-bottom: 1px solid var(--c-border);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {\n color: var(--c-text-1);\n caret-color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {\n background-color: var(--c-bg-card);\n border-left: 1px solid var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {\n color: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {\n background-color: rgba(255, 255, 255, 0.12);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n opacity: 0.9;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {\n opacity: 1;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {\n background-color: transparent;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {\n background-color: var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {\n background-color: rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {\n background-color: rgba(255, 255, 255, 0.3);\n}\n.c-markdown-wrapper .word-count[data-v-b64c492a] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 12px;\n color: var(--c-text-4);\n background: var(--c-bg-card);\n padding: 2px 6px;\n border-radius: 4px;\n z-index: 10;\n}\n.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {\n color: var(--c-error);\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown-
|
|
1
|
+
{"version":3,"file":"C_Markdown-YCAmBbNF.css","names":[],"sources":["../src/components/C_Markdown/index.vue?vue&type=style&index=0&scoped=b64c492a&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */\n.c-markdown-wrapper[data-v-b64c492a] {\n position: relative;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {\n border-radius: 6px;\n border: 1px solid var(--c-border);\n background-color: var(--c-bg-card);\n /* 禁用状态样式 */\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {\n border-color: var(--c-primary);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {\n border-color: var(--c-primary);\n box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {\n background-color: var(--c-bg-disabled, #fafafc);\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {\n background-color: var(--c-bg-card);\n border-bottom: 1px solid var(--c-border);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {\n color: var(--c-text-1);\n caret-color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {\n background-color: var(--c-bg-card);\n border-left: 1px solid var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {\n color: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {\n background-color: rgba(255, 255, 255, 0.12);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n opacity: 0.9;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {\n opacity: 1;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {\n background-color: transparent;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {\n background-color: var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {\n background-color: rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {\n background-color: rgba(255, 255, 255, 0.3);\n}\n.c-markdown-wrapper .word-count[data-v-b64c492a] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 12px;\n color: var(--c-text-4);\n background: var(--c-bg-card);\n padding: 2px 6px;\n border-radius: 4px;\n z-index: 10;\n}\n.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {\n color: var(--c-error);\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_Markdown.css
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
1
|
/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */
|
|
2
|
-
.c-markdown-wrapper[data-v-
|
|
2
|
+
.c-markdown-wrapper[data-v-b64c492a] {
|
|
3
3
|
position: relative;
|
|
4
4
|
}
|
|
5
|
-
.c-markdown-wrapper[data-v-
|
|
5
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {
|
|
6
6
|
border-radius: 6px;
|
|
7
7
|
border: 1px solid var(--c-border);
|
|
8
8
|
background-color: var(--c-bg-card);
|
|
9
9
|
/* 禁用状态样式 */
|
|
10
10
|
}
|
|
11
|
-
.c-markdown-wrapper[data-v-
|
|
11
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {
|
|
12
12
|
border-color: var(--c-primary);
|
|
13
13
|
}
|
|
14
|
-
.c-markdown-wrapper[data-v-
|
|
14
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {
|
|
15
15
|
border-color: var(--c-primary);
|
|
16
16
|
box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));
|
|
17
17
|
}
|
|
18
|
-
.c-markdown-wrapper[data-v-
|
|
18
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {
|
|
19
19
|
background-color: var(--c-bg-disabled, #fafafc);
|
|
20
20
|
cursor: not-allowed;
|
|
21
21
|
}
|
|
22
|
-
.c-markdown-wrapper[data-v-
|
|
22
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {
|
|
23
23
|
cursor: not-allowed;
|
|
24
24
|
}
|
|
25
|
-
.c-markdown-wrapper[data-v-
|
|
25
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {
|
|
26
26
|
background-color: var(--c-bg-card);
|
|
27
27
|
border-bottom: 1px solid var(--c-border);
|
|
28
28
|
}
|
|
29
|
-
.c-markdown-wrapper[data-v-
|
|
29
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {
|
|
30
30
|
background-color: var(--c-bg-card);
|
|
31
31
|
}
|
|
32
|
-
.c-markdown-wrapper[data-v-
|
|
32
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {
|
|
33
33
|
background-color: var(--c-bg-card);
|
|
34
34
|
color: var(--c-text-1);
|
|
35
35
|
}
|
|
36
|
-
.c-markdown-wrapper[data-v-
|
|
36
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {
|
|
37
37
|
color: var(--c-text-1);
|
|
38
38
|
caret-color: var(--c-text-1);
|
|
39
39
|
}
|
|
40
|
-
.c-markdown-wrapper[data-v-
|
|
40
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {
|
|
41
41
|
background-color: var(--c-bg-card);
|
|
42
42
|
}
|
|
43
|
-
.c-markdown-wrapper[data-v-
|
|
43
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {
|
|
44
44
|
background-color: var(--c-bg-card);
|
|
45
45
|
color: var(--c-text-1);
|
|
46
46
|
}
|
|
47
|
-
.c-markdown-wrapper[data-v-
|
|
47
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {
|
|
48
48
|
background-color: var(--c-bg-card);
|
|
49
49
|
border-left: 1px solid var(--c-border);
|
|
50
50
|
}
|
|
51
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
51
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {
|
|
52
52
|
color: #ffffff;
|
|
53
53
|
}
|
|
54
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
54
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {
|
|
55
55
|
background-color: rgba(255, 255, 255, 0.08);
|
|
56
56
|
}
|
|
57
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
57
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {
|
|
58
58
|
background-color: rgba(255, 255, 255, 0.12);
|
|
59
59
|
}
|
|
60
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
60
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {
|
|
61
61
|
fill: #ffffff;
|
|
62
62
|
opacity: 0.9;
|
|
63
63
|
}
|
|
64
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
64
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {
|
|
65
65
|
opacity: 1;
|
|
66
66
|
}
|
|
67
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
67
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {
|
|
68
68
|
background-color: transparent;
|
|
69
69
|
}
|
|
70
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
70
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {
|
|
71
71
|
fill: #ffffff;
|
|
72
72
|
}
|
|
73
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
73
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {
|
|
74
74
|
background-color: rgba(255, 255, 255, 0.08);
|
|
75
75
|
}
|
|
76
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
76
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {
|
|
77
77
|
background-color: var(--c-border);
|
|
78
78
|
}
|
|
79
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
80
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
79
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,
|
|
80
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {
|
|
81
81
|
width: 8px;
|
|
82
82
|
height: 8px;
|
|
83
83
|
}
|
|
84
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
85
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
84
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,
|
|
85
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {
|
|
86
86
|
background-color: rgba(255, 255, 255, 0.05);
|
|
87
87
|
}
|
|
88
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
89
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
88
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,
|
|
89
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {
|
|
90
90
|
background-color: rgba(255, 255, 255, 0.2);
|
|
91
91
|
border-radius: 4px;
|
|
92
92
|
}
|
|
93
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
94
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
93
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,
|
|
94
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {
|
|
95
95
|
background-color: rgba(255, 255, 255, 0.3);
|
|
96
96
|
}
|
|
97
|
-
.c-markdown-wrapper .word-count[data-v-
|
|
97
|
+
.c-markdown-wrapper .word-count[data-v-b64c492a] {
|
|
98
98
|
position: absolute;
|
|
99
99
|
bottom: 8px;
|
|
100
100
|
right: 12px;
|
|
@@ -105,8 +105,8 @@
|
|
|
105
105
|
border-radius: 4px;
|
|
106
106
|
z-index: 10;
|
|
107
107
|
}
|
|
108
|
-
.c-markdown-wrapper .word-count.exceed[data-v-
|
|
108
|
+
.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {
|
|
109
109
|
color: var(--c-error);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
/*# sourceMappingURL=C_Markdown-
|
|
112
|
+
/*# sourceMappingURL=C_Markdown-Kujzx1qG.css.map*/
|
package/dist/C_Markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"8hCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,GAAA,EAAA,EAAA,KAAqB,KAAK,CAC1B,GAAA,EAAA,EAAA,KAAiB,GAAG,CAEpB,GAAA,EAAA,EAAA,cACG,EAAM,YAAY,QAAU,EACnC,CAEI,GAAA,EAAA,EAAA,cAA2C,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACX,CACD,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAmB,CAChD,GACJ,EAEF,EAAA,EAAA,eAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAO,EAEpD,EAEF,EAAA,EAAA,WACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAE,EAGpD,CAAE,UAAW,GAAM,CACpB,CAED,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAU,CAC1D,OAEF,EAAK,oBAAqB,EAAM,CAC5B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAO,EAIrC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAK,CACtB,EAAM,UACR,EAAS,EAAK,EAIZ,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAK,EAGpB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAM,EAG3C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAa,EAGnC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAK,EAG7B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAc,CAC9C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAK,EACtB,EAAM,iBAAiB,SAkB5B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAO,EAgBxB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAE,EAOH,YACD,CAAC,oDArLI,MAAA,CAzBJ,OAAA,EAAA,EAAA,gBAAK,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAuBzB,EAAA,QAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|
|
1
|
+
{"version":3,"file":"C_Markdown.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"8hCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,GAAA,EAAA,EAAA,KAAqB,KAAI,CACzB,GAAA,EAAA,EAAA,KAAiB,GAAE,CAEnB,GAAA,EAAA,EAAA,cACG,EAAM,YAAY,QAAU,EACpC,CAEK,GAAA,EAAA,EAAA,cAA2C,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACZ,CACA,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAkB,CAC/C,GACL,EAED,EAAA,EAAA,eAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAM,EAEpD,EAED,EAAA,EAAA,WACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAC,EAGnD,CAAE,UAAW,GAAK,CACpB,CAEA,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAS,CACzD,OAEF,EAAK,oBAAqB,EAAK,CAC3B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAM,EAIpC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAI,CACrB,EAAM,UACR,EAAS,EAAI,EAIX,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAI,EAGnB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAK,EAG1C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAY,EAGlC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAI,EAG5B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAa,CAC7C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAI,EACrB,EAAM,iBAAgB,SAkB3B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAM,EAgBvB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAC,EAOF,YACD,CAAA,oDArLK,MAAA,CAzBJ,OAAA,EAAA,EAAA,gBAAK,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAuBzB,EAAA,QAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|
package/dist/C_Markdown2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./export-helper.js";import{computed as t,createElementBlock as n,createVNode as r,defineComponent as i,normalizeClass as a,onMounted as o,openBlock as s,ref as c,unref as l,watch as u}from"vue";import d from"@kangc/v-md-editor";var f=e(i({name:`C_Markdown`,__name:`index`,props:{modelValue:{default:``},height:{default:`400px`},disabled:{type:Boolean,default:!1},placeholder:{default:`请输入 Markdown 内容...`},mode:{default:`editable`},toolbar:{},uploadImageConfig:{},tocNavPosition:{default:`right`},defaultFullscreen:{type:Boolean,default:!1},autofocus:{type:Boolean,default:!1},includeLevel:{default:()=>[1,2,3,4,5,6]},leftToolbar:{default:`undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save`},rightToolbar:{default:`preview toc sync-scroll fullscreen`},maxLength:{default:5e4},showWordCount:{type:Boolean,default:!0},autoSave:{type:Boolean,default:!1},autoSaveInterval:{default:3e4},isDark:{type:Boolean,default:!1}},emits:[`update:modelValue`,`change`,`save`,`upload-image`,`fullscreen-change`,`copy-code-success`,`word-count-change`,`auto-save`,`max-length-exceeded`],setup(e,{expose:i,emit:f}){let p=e,m=f,h=c(null),g=c(``),_=t(()=>p.modelValue?.length||0),v=t(()=>{let e={accept:`image/*`,multiple:!1};return p.uploadImageConfig?{...e,...p.uploadImageConfig}:e});o(()=>{p.showWordCount&&p.modelValue&&m(`word-count-change`,p.modelValue.length)}),u(()=>p.modelValue,e=>{p.showWordCount&&m(`word-count-change`,e?.length||0)},{immediate:!0});let y=e=>{if(e.length>p.maxLength){m(`max-length-exceeded`,e.length,p.maxLength);return}m(`update:modelValue`,e),p.showWordCount&&m(`word-count-change`,e.length)},b=(e,t)=>{g.value=t,m(`change`,e,t),p.autoSave&&E(e)},x=(e,t)=>{m(`save`,e,t)},S=(e,t,n)=>{m(`upload-image`,e,t,n)},C=e=>{m(`fullscreen-change`,e)},w=e=>{m(`copy-code-success`,e)},T=null,E=e=>{T&&clearTimeout(T),T=setTimeout(()=>{m(`auto-save`,e)},p.autoSaveInterval)};return i({focus:()=>{h.value?.focus()},getHtml:()=>g.value,insertText:e=>{h.value?.insert(t=>({text:`${t}${e}`,selected:e}))},wordCount:_}),(e,t)=>(s(),n(`div`,{class:a([`c-markdown-wrapper`,{"is-dark":e.isDark}])},[r(l(d),{ref_key:`editorRef`,ref:h,"model-value":e.modelValue,height:e.height,placeholder:e.placeholder,toolbar:e.toolbar,mode:e.mode,"upload-image-config":v.value,"toc-nav-position":e.tocNavPosition,"default-fullscreen":e.defaultFullscreen,autofocus:e.autofocus,"include-level":e.includeLevel,"left-toolbar":e.leftToolbar,"right-toolbar":e.rightToolbar,"default-show-toc":!0,"onUpdate:modelValue":y,onChange:b,onSave:x,onUploadImage:S,onFullscreenChange:C,onCopyCodeSuccess:w},null,8,[`model-value`,`height`,`placeholder`,`toolbar`,`mode`,`upload-image-config`,`toc-nav-position`,`default-fullscreen`,`autofocus`,`include-level`,`left-toolbar`,`right-toolbar`])],2))}}),[[`__scopeId`,`data-v-
|
|
1
|
+
import{t as e}from"./export-helper.js";import{computed as t,createElementBlock as n,createVNode as r,defineComponent as i,normalizeClass as a,onMounted as o,openBlock as s,ref as c,unref as l,watch as u}from"vue";import d from"@kangc/v-md-editor";var f=e(i({name:`C_Markdown`,__name:`index`,props:{modelValue:{default:``},height:{default:`400px`},disabled:{type:Boolean,default:!1},placeholder:{default:`请输入 Markdown 内容...`},mode:{default:`editable`},toolbar:{},uploadImageConfig:{},tocNavPosition:{default:`right`},defaultFullscreen:{type:Boolean,default:!1},autofocus:{type:Boolean,default:!1},includeLevel:{default:()=>[1,2,3,4,5,6]},leftToolbar:{default:`undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save`},rightToolbar:{default:`preview toc sync-scroll fullscreen`},maxLength:{default:5e4},showWordCount:{type:Boolean,default:!0},autoSave:{type:Boolean,default:!1},autoSaveInterval:{default:3e4},isDark:{type:Boolean,default:!1}},emits:[`update:modelValue`,`change`,`save`,`upload-image`,`fullscreen-change`,`copy-code-success`,`word-count-change`,`auto-save`,`max-length-exceeded`],setup(e,{expose:i,emit:f}){let p=e,m=f,h=c(null),g=c(``),_=t(()=>p.modelValue?.length||0),v=t(()=>{let e={accept:`image/*`,multiple:!1};return p.uploadImageConfig?{...e,...p.uploadImageConfig}:e});o(()=>{p.showWordCount&&p.modelValue&&m(`word-count-change`,p.modelValue.length)}),u(()=>p.modelValue,e=>{p.showWordCount&&m(`word-count-change`,e?.length||0)},{immediate:!0});let y=e=>{if(e.length>p.maxLength){m(`max-length-exceeded`,e.length,p.maxLength);return}m(`update:modelValue`,e),p.showWordCount&&m(`word-count-change`,e.length)},b=(e,t)=>{g.value=t,m(`change`,e,t),p.autoSave&&E(e)},x=(e,t)=>{m(`save`,e,t)},S=(e,t,n)=>{m(`upload-image`,e,t,n)},C=e=>{m(`fullscreen-change`,e)},w=e=>{m(`copy-code-success`,e)},T=null,E=e=>{T&&clearTimeout(T),T=setTimeout(()=>{m(`auto-save`,e)},p.autoSaveInterval)};return i({focus:()=>{h.value?.focus()},getHtml:()=>g.value,insertText:e=>{h.value?.insert(t=>({text:`${t}${e}`,selected:e}))},wordCount:_}),(e,t)=>(s(),n(`div`,{class:a([`c-markdown-wrapper`,{"is-dark":e.isDark}])},[r(l(d),{ref_key:`editorRef`,ref:h,"model-value":e.modelValue,height:e.height,placeholder:e.placeholder,toolbar:e.toolbar,mode:e.mode,"upload-image-config":v.value,"toc-nav-position":e.tocNavPosition,"default-fullscreen":e.defaultFullscreen,autofocus:e.autofocus,"include-level":e.includeLevel,"left-toolbar":e.leftToolbar,"right-toolbar":e.rightToolbar,"default-show-toc":!0,"onUpdate:modelValue":y,onChange:b,onSave:x,onUploadImage:S,onFullscreenChange:C,onCopyCodeSuccess:w},null,8,[`model-value`,`height`,`placeholder`,`toolbar`,`mode`,`upload-image-config`,`toc-nav-position`,`default-fullscreen`,`autofocus`,`include-level`,`left-toolbar`,`right-toolbar`])],2))}}),[[`__scopeId`,`data-v-b64c492a`]]);export{f as t};
|
|
2
2
|
//# sourceMappingURL=C_Markdown2.js.map
|