npmapps 1.1.4 → 1.1.5

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.
Files changed (114) hide show
  1. package/app/wujie-vue2-child/.eslintrc.js +19 -0
  2. package/app/wujie-vue2-child/README.md +24 -0
  3. package/app/wujie-vue2-child/babel.config.js +5 -0
  4. package/app/wujie-vue2-child/docs/superpowers/plans/2026-05-29-quill-editor.md +836 -0
  5. package/app/wujie-vue2-child/docs/superpowers/specs/2026-05-29-quill-editor-design.md +210 -0
  6. package/app/wujie-vue2-child/jsconfig.json +19 -0
  7. package/app/wujie-vue2-child/package-lock.json +21333 -0
  8. package/app/wujie-vue2-child/package.json +63 -0
  9. package/app/wujie-vue2-child/postcss.config.js +10 -0
  10. package/app/wujie-vue2-child/public/favicon.ico +0 -0
  11. package/app/wujie-vue2-child/public/index.html +17 -0
  12. package/app/wujie-vue2-child/public/rili.jpg +0 -0
  13. package/app/wujie-vue2-child/public//344/270/200/351/224/256/351/273/221/346/232/227.html +136 -0
  14. package/app/wujie-vue2-child/src/App.vue +110 -0
  15. package/app/wujie-vue2-child/src/assets/bpmn-camunda.jpg +0 -0
  16. package/app/wujie-vue2-child/src/assets/css/diagram.less +17 -0
  17. package/app/wujie-vue2-child/src/assets/icon/Icon.less +31 -0
  18. package/app/wujie-vue2-child/src/assets/icon/font/app-codes.css +26 -0
  19. package/app/wujie-vue2-child/src/assets/icon/font/app.eot +0 -0
  20. package/app/wujie-vue2-child/src/assets/icon/font/app.svg +60 -0
  21. package/app/wujie-vue2-child/src/assets/icon/font/app.ttf +0 -0
  22. package/app/wujie-vue2-child/src/assets/icon/font/app.woff +0 -0
  23. package/app/wujie-vue2-child/src/assets/icon/font/app.woff2 +0 -0
  24. package/app/wujie-vue2-child/src/assets/icon/font/config.json +248 -0
  25. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-bottom-tool.svg +30 -0
  26. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-horizontal-center-tool.svg +85 -0
  27. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-left-tool.svg +84 -0
  28. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-right-tool.svg +80 -0
  29. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-top-tool.svg +84 -0
  30. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/align-vertical-center-tool.svg +89 -0
  31. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/distribute-horizontally-tool.svg +95 -0
  32. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/distribute-vertically-tool.svg +99 -0
  33. package/app/wujie-vue2-child/src/assets/icon/font/source/raw/set-color-tool.svg +111 -0
  34. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-bottom-tool.svg +30 -0
  35. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-horizontal-center-tool.svg +30 -0
  36. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-left-tool.svg +30 -0
  37. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-right-tool.svg +30 -0
  38. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-top-tool.svg +30 -0
  39. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/align-vertical-center-tool.svg +30 -0
  40. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/distribute-horizontally-tool.svg +30 -0
  41. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/distribute-vertically-tool.svg +30 -0
  42. package/app/wujie-vue2-child/src/assets/icon/font/source/symbols/set-color-tool.svg +63 -0
  43. package/app/wujie-vue2-child/src/assets/logo.png +0 -0
  44. package/app/wujie-vue2-child/src/components/EllTable/README.md +70 -0
  45. package/app/wujie-vue2-child/src/components/EllTable/article.md +184 -0
  46. package/app/wujie-vue2-child/src/components/EllTable/index.js +213 -0
  47. package/app/wujie-vue2-child/src/components/EventCalendar/CalendarSkeleton.vue +147 -0
  48. package/app/wujie-vue2-child/src/components/EventCalendar/CodeBlock.vue +199 -0
  49. package/app/wujie-vue2-child/src/components/EventCalendar/MonthSelect.vue +376 -0
  50. package/app/wujie-vue2-child/src/components/EventCalendar/README.md +368 -0
  51. package/app/wujie-vue2-child/src/components/EventCalendar/example.vue +1551 -0
  52. package/app/wujie-vue2-child/src/components/EventCalendar/index.vue +1646 -0
  53. package/app/wujie-vue2-child/src/components/EventCalendar/mockData.js +349 -0
  54. package/app/wujie-vue2-child/src/components/EventCalendar/utils.js +201 -0
  55. package/app/wujie-vue2-child/src/components/FormulaEditor/FunctionSelector.vue +123 -0
  56. package/app/wujie-vue2-child/src/components/FormulaEditor/OperatorSelector.vue +184 -0
  57. package/app/wujie-vue2-child/src/components/FormulaEditor/ParameterSelector.vue +123 -0
  58. package/app/wujie-vue2-child/src/components/FormulaEditor/api.js +69 -0
  59. package/app/wujie-vue2-child/src/components/FormulaEditor/index.vue +435 -0
  60. package/app/wujie-vue2-child/src/components/HelloWorld.vue +58 -0
  61. package/app/wujie-vue2-child/src/components/PageHeader/index.vue +158 -0
  62. package/app/wujie-vue2-child/src/components/Splitter/README.md +144 -0
  63. package/app/wujie-vue2-child/src/components/Splitter/example.vue +84 -0
  64. package/app/wujie-vue2-child/src/components/Splitter/index.vue +203 -0
  65. package/app/wujie-vue2-child/src/components/diagram/ToolBar.vue +357 -0
  66. package/app/wujie-vue2-child/src/components/diagram/customTranslate/customTranslate.js +12 -0
  67. package/app/wujie-vue2-child/src/components/diagram/customTranslate/translationsGerman.js +241 -0
  68. package/app/wujie-vue2-child/src/components/diagram/index.vue +261 -0
  69. package/app/wujie-vue2-child/src/components/diagram/xmlData.js +29 -0
  70. package/app/wujie-vue2-child/src/directives/filldown.js +155 -0
  71. package/app/wujie-vue2-child/src/directives/filldownTable.js +291 -0
  72. package/app/wujie-vue2-child/src/main.js +40 -0
  73. package/app/wujie-vue2-child/src/router/index.js +72 -0
  74. package/app/wujie-vue2-child/src/store/index.js +23 -0
  75. package/app/wujie-vue2-child/src/utils/winBox.js +23 -0
  76. package/app/wujie-vue2-child/src/views/Extend/A.vue +12 -0
  77. package/app/wujie-vue2-child/src/views/Extend/B.vue +10 -0
  78. package/app/wujie-vue2-child/src/views/Extend/MagicalComponentsForELFormItem.vue +78 -0
  79. package/app/wujie-vue2-child/src/views/Extend/index.vue +59 -0
  80. package/app/wujie-vue2-child/src/views/Extend/tableMouseHorizontalWheel.vue +184 -0
  81. package/app/wujie-vue2-child/src/views/Home.vue +27 -0
  82. package/app/wujie-vue2-child/src/views/RouterJump.vue +145 -0
  83. package/app/wujie-vue2-child/src/views/calendar/index.vue +19 -0
  84. package/app/wujie-vue2-child/src/views/css.vue +57 -0
  85. package/app/wujie-vue2-child/src/views/cssComponents/EllipsisText.vue +73 -0
  86. package/app/wujie-vue2-child/src/views/cssComponents/HoverCard.vue +69 -0
  87. package/app/wujie-vue2-child/src/views/cssComponents/TableHover.vue +130 -0
  88. package/app/wujie-vue2-child/src/views/cssComponents/inputSlo.vue +42 -0
  89. package/app/wujie-vue2-child/src/views/cssComponents/tableFixed.vue +148 -0
  90. package/app/wujie-vue2-child/src/views/echarts/echart-dome.vue +73 -0
  91. package/app/wujie-vue2-child/src/views/echarts/index.vue +118 -0
  92. package/app/wujie-vue2-child/src/views/echarts/pei3d.vue +658 -0
  93. package/app/wujie-vue2-child/src/views/element/bpmn/index.vue +15 -0
  94. package/app/wujie-vue2-child/src/views/element/components/attendanceCycle/index.vue +131 -0
  95. package/app/wujie-vue2-child/src/views/element/components/attendanceGroup/index.vue +147 -0
  96. package/app/wujie-vue2-child/src/views/element/components/attendancePersonnel/index.vue +158 -0
  97. package/app/wujie-vue2-child/src/views/element/components/companyCalendar/index.vue +147 -0
  98. package/app/wujie-vue2-child/src/views/element/components/shift/index.vue +147 -0
  99. package/app/wujie-vue2-child/src/views/element/components/shiftRotationSystem/index.vue +147 -0
  100. package/app/wujie-vue2-child/src/views/element/elTableJsx/columnManagement.vue +340 -0
  101. package/app/wujie-vue2-child/src/views/element/elTableJsx/dialogInput.vue +71 -0
  102. package/app/wujie-vue2-child/src/views/element/elTableJsx/elTableJsx.vue +1826 -0
  103. package/app/wujie-vue2-child/src/views/element/elTableJsx/formTable.vue +595 -0
  104. package/app/wujie-vue2-child/src/views/element/elTableJsx/index.vue +29 -0
  105. package/app/wujie-vue2-child/src/views/element/elTableJsx/simpleTable.vue +189 -0
  106. package/app/wujie-vue2-child/src/views/element/elTableJsx.zip +0 -0
  107. package/app/wujie-vue2-child/src/views/element/index.vue +39 -0
  108. package/app/wujie-vue2-child/src/views/element/quillEditor/README.md +163 -0
  109. package/app/wujie-vue2-child/src/views/element/quillEditor/example.vue +307 -0
  110. package/app/wujie-vue2-child/src/views/element/quillEditor/index.vue +409 -0
  111. package/app/wujie-vue2-child/src/views/element/quillEditor/toolbar.js +122 -0
  112. package/app/wujie-vue2-child/vue.config.js +15 -0
  113. package/package.json +1 -1
  114. package/app/check-import-case.js +0 -344
@@ -0,0 +1,189 @@
1
+ <template>
2
+ <div>
3
+ <elTableJsx
4
+ :columns="columns"
5
+ :tableData="tableData"
6
+ stripe
7
+ @cell-click="onCellClick"
8
+ >
9
+ <template #header-left>
10
+ <span>header-left</span>
11
+ </template>
12
+ <!-- <template #header-right>
13
+ <span>header-right</span>
14
+ </template> -->
15
+ </elTableJsx>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+ import elTableJsx from "./elTableJsx.vue";
21
+ export default {
22
+ components: {
23
+ elTableJsx,
24
+ },
25
+ data() {
26
+ return {
27
+ columns: [
28
+ {
29
+ label: "基本信息",
30
+ key: "basic",
31
+ width: "600",
32
+ props: {
33
+ align: "center",
34
+ },
35
+ children: [
36
+ {
37
+ label: "姓名",
38
+ key: "name",
39
+ props: {
40
+ align: "center",
41
+ width: "220",
42
+ },
43
+ },
44
+ {
45
+ label: "性别",
46
+ key: "gender",
47
+ props: {
48
+ align: "center",
49
+ width: "180",
50
+ },
51
+ },
52
+ {
53
+ label: "年龄",
54
+ key: "age",
55
+ props: {
56
+ align: "center",
57
+ width: "180",
58
+ },
59
+ },
60
+ ],
61
+ },
62
+
63
+ {
64
+ label: "电话",
65
+ key: "phone",
66
+ props: {
67
+ align: "center",
68
+ minWidth: "250",
69
+ },
70
+ },
71
+ {
72
+ label: "邮箱",
73
+ key: "email",
74
+ props: {
75
+ align: "center",
76
+ minWidth: "300",
77
+ },
78
+ },
79
+ {
80
+ label: "住址",
81
+ key: "address",
82
+ props: {
83
+ align: "center",
84
+ minWidth: "350",
85
+ },
86
+ },
87
+
88
+ {
89
+ label: "部门",
90
+ key: "department",
91
+ props: {
92
+ align: "center",
93
+ minWidth: "250",
94
+ },
95
+ },
96
+ {
97
+ label: "职位",
98
+ key: "position",
99
+ props: {
100
+ align: "center",
101
+ minWidth: "250",
102
+ },
103
+ },
104
+ {
105
+ label: "入职时间",
106
+ key: "entryDate",
107
+ props: {
108
+ align: "center",
109
+ minWidth: "250",
110
+ },
111
+ },
112
+ ],
113
+ tableData: [
114
+ {
115
+ name: "张三",
116
+ gender: "男",
117
+ age: 28,
118
+ phone: "13812345678",
119
+ email: "zhangsan@example.com",
120
+ address: "北京市海淀区中关村大街1号",
121
+ department: "研发部",
122
+ position: "高级工程师",
123
+ entryDate: "2020-01-15",
124
+ },
125
+ {
126
+ name: "李四",
127
+ gender: "女",
128
+ age: 32,
129
+ phone: "13987654321",
130
+ email: "lisi@example.com",
131
+ address: "上海市浦东新区陆家嘴环路888号",
132
+ department: "产品部",
133
+ position: "产品经理",
134
+ entryDate: "2019-06-20",
135
+ },
136
+ {
137
+ name: "王五",
138
+ gender: "男",
139
+ age: 35,
140
+ phone: "13567891234",
141
+ email: "wangwu@example.com",
142
+ address: "广州市天河区珠江新城华夏路10号",
143
+ department: "市场部",
144
+ position: "市场总监",
145
+ entryDate: "2018-03-10",
146
+ },
147
+ {
148
+ name: "赵六",
149
+ gender: "女",
150
+ age: 26,
151
+ phone: "13789012345",
152
+ email: "zhaoliu@example.com",
153
+ address: "深圳市南山区科技园科发路8号",
154
+ department: "设计部",
155
+ position: "UI设计师",
156
+ entryDate: "2021-09-01",
157
+ },
158
+ {
159
+ name: "钱七",
160
+ gender: "男",
161
+ age: 40,
162
+ phone: "13456789012",
163
+ email: "qianqi@example.com",
164
+ address: "成都市武侯区天府大道1234号",
165
+ department: "财务部",
166
+ position: "财务总监",
167
+ entryDate: "2017-12-05",
168
+ },
169
+ {
170
+ name: "孙八",
171
+ gender: "女",
172
+ age: 29,
173
+ phone: "13234567890",
174
+ email: "sunba@example.com",
175
+ address: "武汉市江汉区解放大道456号",
176
+ department: "人力资源部",
177
+ position: "HR经理",
178
+ entryDate: "2020-07-15",
179
+ },
180
+ ],
181
+ };
182
+ },
183
+ methods: {
184
+ onCellClick(row, column, cell, event) {
185
+ console.log("onCellClick", row, column, cell, event);
186
+ },
187
+ },
188
+ };
189
+ </script>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <div>
3
+ <el-tabs type="border-card" v-model="activeName">
4
+ <el-tab-pane label="BPMN">
5
+ <bpmn />
6
+ </el-tab-pane>
7
+ <el-tab-pane label="分屏示例">
8
+ <SplitterExample />
9
+ </el-tab-pane>
10
+ <el-tab-pane label="JSX表格">
11
+ <elTableJsx />
12
+ </el-tab-pane>
13
+ <el-tab-pane label="富文本编辑器" name="quillEditor">
14
+ <quillEditor />
15
+ </el-tab-pane>
16
+ </el-tabs>
17
+ </div>
18
+ </template>
19
+
20
+ <script>
21
+ import bpmn from "./bpmn/index.vue";
22
+ import SplitterExample from "../../components/Splitter/example.vue";
23
+ import elTableJsx from "./elTableJsx/index.vue";
24
+ import quillEditor from "./quillEditor/example.vue";
25
+ export default {
26
+ name: "element",
27
+ components: {
28
+ bpmn,
29
+ SplitterExample,
30
+ elTableJsx,
31
+ quillEditor,
32
+ },
33
+ data() {
34
+ return {
35
+ activeName: "quillEditor",
36
+ };
37
+ },
38
+ };
39
+ </script>
@@ -0,0 +1,163 @@
1
+ # QuillEditor
2
+
3
+ 基于 Quill2.x + quill-table-better 的 Vue2 富文本编辑器组件,支持表格、图片、全部基础格式。
4
+
5
+ ## 安装依赖
6
+
7
+ 依赖已添加到 `package.json`,首次使用需安装:
8
+
9
+ ```bash
10
+ npm install
11
+ ```
12
+
13
+ 依赖列表:
14
+ - `quill@2.0.2`
15
+ - `quill-table-better@1.2.3`
16
+
17
+ ##快速使用
18
+
19
+ ```vue
20
+ <template>
21
+ <QuillEditor v-model="content" :height="400" />
22
+ </template>
23
+
24
+ <script>
25
+ import QuillEditor from '@/views/element/quillEditor/index.vue';
26
+
27
+ export default {
28
+ components: { QuillEditor },
29
+ data() {
30
+ return { content: '<p>Hello Quill!</p>' };
31
+ },
32
+ };
33
+ </script>
34
+ ```
35
+
36
+ ## Props
37
+
38
+ | Prop | 类型 | 默认值 | 说明 |
39
+ |------|------|--------|------|
40
+ | `value` | String | `''` | 编辑器 HTML 内容,支持 v-model |
41
+ | `placeholder` | String | `'请输入内容...'` | 占位文字 |
42
+ | `readonly` | Boolean | `false` | 是否只读(可看不可改) |
43
+ | `disabled` | Boolean | `false` | 是否禁用(工具栏灰掉,不可编辑) |
44
+ | `height` | String \| Number | `300` | 编辑区高度,数字按 px,字符串按原值 |
45
+ | `toolbarPreset` | String | `'default'` | 工具栏预设:`'simple'`(精简)/ `'default'`(默认)/ `'full'`(全部) |
46
+ | `toolbar` | Array \| Object | `null` | 自定义工具栏配置;传了则**覆盖** `toolbarPreset` |
47
+ | `imageHandler` | Function | `null` | 自定义图片处理函数;不传则走 base64 内联 |
48
+ | `theme` | String | `'snow'` |主题,目前只支持 snow |
49
+
50
+ ## Events
51
+
52
+ |事件 |触发时机 | 参数 |
53
+ |------|---------|------|
54
+ | `input` | 内容变化 | `(html: String)` |
55
+ | `change` | 内容变化(去抖300ms) | `(html: String)` |
56
+ | `ready` | Quill 实例初始化完成 | `(quill: Quill)` |
57
+ | `focus` | 编辑器获得焦点 | `()` |
58
+ | `blur` | 编辑器失去焦点 | `()` |
59
+
60
+ ## Methods(通过 ref 调用)
61
+
62
+ | 方法 | 返回值 | 说明 |
63
+ |------|--------|------|
64
+ | `getHtml()` | String | 获取当前 HTML |
65
+ | `getText()` | String | 获取纯文本 |
66
+ | `setHtml(html)` | - | 设置内容 |
67
+ | `clear()` | - | 清空内容 |
68
+ | `focus()` | - |聚焦 |
69
+ | `getQuill()` | Quill | 获取底层 Quill 实例(高级用法) |
70
+
71
+ ## 自定义图片上传示例
72
+
73
+ ```vue
74
+ <QuillEditor
75
+ v-model="content"
76
+ :image-handler="uploadImage"
77
+ />
78
+
79
+ <script>
80
+ methods: {
81
+ async uploadImage(file, range, quill) {
82
+ const form = new FormData();
83
+ form.append('file', file);
84
+ const res = await fetch('/api/upload', { method: 'POST', body: form });
85
+ const { url } = await res.json();
86
+ quill.insertEmbed(range.index, 'image', url);
87
+ return true; // 返回 true 表示已处理,跳过 base64 回退
88
+ },
89
+ }
90
+ </script>
91
+ ```
92
+
93
+ ## 工具栏预设(toolbarPreset)
94
+
95
+ 通过 `toolbarPreset` 选择内置工具栏,三档从简到全:
96
+
97
+ | 预设 | 适用场景 | 包含按钮 |
98
+ |------|---------|----------|
99
+ | `simple` 精简 | 评论、备注等轻量输入 | 加粗/斜体/下划线、标题(1-3)、有序/无序列表、链接、清除格式 |
100
+ | `default` 默认 | 大多数业务表单(默认值) | 标题/字号、基础格式+删除线、颜色/背景、引用/代码、列表、缩进、对齐、链接/图片、清除、撤销/重做 |
101
+ | `full` 全部 | 文档/文章等富内容 | 在默认基础上再加 上标/下标、视频、表格 |
102
+
103
+ ```vue
104
+ <QuillEditor :toolbar-preset="'simple'" /> <!-- 精简 -->
105
+ <QuillEditor /> <!-- 默认 -->
106
+ <QuillEditor :toolbar-preset="'full'" /> <!-- 全部 -->
107
+ ```
108
+
109
+ > 运行时切换 `toolbarPreset` 需重新挂载组件(给组件加 `:key="preset"`),因为 Quill 工具栏在初始化时一次性构建。
110
+
111
+ 各按钮 token 的功能对照、以及为何预设不含 `font` 字体下拉,见 `toolbar.js` 顶部注释。
112
+
113
+ ### 完全自定义工具栏
114
+
115
+ 传 `toolbar` 数组(优先级高于 `toolbarPreset`):
116
+
117
+ ```javascript
118
+ [
119
+ [{ header: [1, 2, 3, false] }],
120
+ ['bold', 'italic', 'underline'],
121
+ [{ list: 'ordered' }, { list: 'bullet' }],
122
+ ['link', 'clean'],
123
+ ]
124
+ ```
125
+
126
+ ## HTML 源码双向联动
127
+
128
+ 内容用 v-model 双向绑定,可同时在一个 textarea 里编辑 HTML 源码并写回编辑器:
129
+
130
+ ```vue
131
+ <template>
132
+ <QuillEditor v-model="html" />
133
+ <textarea v-model="source" />
134
+ <button @click="html = source">应用源码到编辑器</button>
135
+ </template>
136
+
137
+ <script>
138
+ export default {
139
+ data() {
140
+ return { html: '<p>hello</p>', source: '<p>hello</p>' };
141
+ },
142
+ watch: {
143
+ html(val) { this.source = val; }, // 编辑器变化实时同步到源码框
144
+ },
145
+ };
146
+ </script>
147
+ ```
148
+
149
+ > 写回时 `html = source` 会触发编辑器 `setHtml`,Quill 会对 HTML 做规范化。完整示例见 `example.vue` 卡片②。
150
+
151
+ ##表格功能
152
+
153
+ 点击工具栏的 `table-better`按钮可插入表格,右键单元格可弹出操作菜单(增删行列、合并/拆分、单元格背景色、复制/删除)。
154
+
155
+ 表格配置见 `toolbar.js` 中 `defaultTableBetterConfig`:
156
+ - `language: 'zh_CN'` 中文界面
157
+ - `toolbarTable: true` 显示表格工具栏
158
+ - `menus`包含 column/row/merge/table/cell/wrap/copy/delete全部操作
159
+
160
+ ##主题与样式
161
+
162
+ 组件内部已 `import 'quill/dist/quill.snow.css'` 和 `quill-table-better/dist/quill-table-better.css`,
163
+ **不需要在 main.js 全局引入**。外层容器样式 scoped,不污染全局。
@@ -0,0 +1,307 @@
1
+ <template>
2
+ <div class="quill-demo">
3
+ <!-- 卡片① 工具栏预设切换 -->
4
+ <el-card class="demo-card" shadow="never">
5
+ <div slot="header" class="demo-card__header">
6
+ <span class="demo-card__title">① 工具栏预设切换(toolbarPreset)</span>
7
+ <el-radio-group v-model="presetMode" size="small">
8
+ <el-radio-button label="simple">精简</el-radio-button>
9
+ <el-radio-button label="default">默认</el-radio-button>
10
+ <el-radio-button label="full">全部</el-radio-button>
11
+ </el-radio-group>
12
+ </div>
13
+ <p class="demo-tip">
14
+ 切换上方单选即可实时更换工具栏。当前预设:<b>{{ presetMode }}</b>
15
+ (组件通过 <code>:key</code> 重新挂载以应用新工具栏,内容经 v-model 自动保留)。
16
+ </p>
17
+ <QuillEditor
18
+ :key="presetMode"
19
+ v-model="presetContent"
20
+ :toolbar-preset="presetMode"
21
+ :height="240"
22
+ />
23
+ </el-card>
24
+
25
+ <!-- 卡片② 基础编辑器 + HTML 源码联动 -->
26
+ <el-card class="demo-card" shadow="never">
27
+ <div slot="header" class="demo-card__title">② 基础编辑器 + HTML 源码联动(实例1)</div>
28
+ <QuillEditor v-model="content1" :height="260" @ready="onReady" />
29
+ <div class="source-head">
30
+ <span class="demo-card__subtitle">HTML 源码(可编辑)</span>
31
+ <div>
32
+ <el-button type="primary" size="small" @click="applySource">应用到编辑器1</el-button>
33
+ <el-button size="small" @click="refreshSource">从编辑器1刷新源码</el-button>
34
+ </div>
35
+ </div>
36
+ <el-input
37
+ v-model="source1"
38
+ type="textarea"
39
+ :rows="6"
40
+ class="source-box"
41
+ placeholder="在此编辑 HTML,点「应用到编辑器1」整体写回上方编辑器"
42
+ />
43
+ <p class="demo-tip">
44
+ 编辑器1 的内容变化会实时同步到源码框;点「应用到编辑器1」把源码整体写回编辑器(Quill 会规范化 HTML)。
45
+ </p>
46
+ </el-card>
47
+
48
+ <!-- 卡片③ 只读 / 禁用 -->
49
+ <el-card class="demo-card" shadow="never">
50
+ <div slot="header" class="demo-card__title">③ 只读 / 禁用模式</div>
51
+ <el-row :gutter="16">
52
+ <el-col :span="12">
53
+ <div class="demo-card__subtitle">只读 readonly(可选可看,不可改)</div>
54
+ <QuillEditor v-model="content2" :readonly="true" :height="220" />
55
+ </el-col>
56
+ <el-col :span="12">
57
+ <div class="demo-card__subtitle">禁用 disabled(整体灰掉)</div>
58
+ <QuillEditor v-model="content3" :disabled="true" :height="220" />
59
+ </el-col>
60
+ </el-row>
61
+ </el-card>
62
+
63
+ <!-- 卡片④ 自定义工具栏 -->
64
+ <el-card class="demo-card" shadow="never">
65
+ <div slot="header" class="demo-card__title">④ 自定义工具栏(传 toolbar 数组)</div>
66
+ <p class="demo-tip">
67
+ 传入 <code>:toolbar</code> 数组即可完全自定义(优先级高于 toolbarPreset)。本例只保留:加粗 / 斜体、列表、链接、清除。
68
+ </p>
69
+ <QuillEditor :toolbar="customToolbar" v-model="content4" :height="200" />
70
+ </el-card>
71
+
72
+ <!-- 卡片⑤ Ref 方法调用 -->
73
+ <el-card class="demo-card" shadow="never">
74
+ <div slot="header" class="demo-card__title">⑤ 通过 ref 调用组件方法</div>
75
+ <QuillEditor ref="refDemo" v-model="content5" toolbar-preset="simple" :height="180" />
76
+ <div class="btn-row">
77
+ <el-button size="small" @click="callGetHtml">getHtml()</el-button>
78
+ <el-button size="small" @click="callGetText">getText()</el-button>
79
+ <el-button size="small" @click="callClear">clear()</el-button>
80
+ <el-button size="small" @click="callFocus">focus()</el-button>
81
+ </div>
82
+ <el-input
83
+ v-model="methodOutput"
84
+ type="textarea"
85
+ :rows="4"
86
+ readonly
87
+ class="source-box"
88
+ placeholder="方法返回值显示在这里"
89
+ />
90
+ </el-card>
91
+
92
+ <!-- 卡片⑥ 事件监听 -->
93
+ <el-card class="demo-card" shadow="never">
94
+ <div slot="header" class="demo-card__header">
95
+ <span class="demo-card__title">⑥ 事件监听(focus / blur / change)</span>
96
+ <el-button size="small" @click="eventLogs = []">清空日志</el-button>
97
+ </div>
98
+ <QuillEditor
99
+ v-model="content6"
100
+ toolbar-preset="simple"
101
+ :height="180"
102
+ @focus="onEvtFocus"
103
+ @blur="onEvtBlur"
104
+ @change="onEvtChange"
105
+ />
106
+ <div class="log-panel">
107
+ <div v-if="!eventLogs.length" class="log-empty">(在上方编辑器中操作以触发事件)</div>
108
+ <div v-for="(log, i) in eventLogs" :key="i" class="log-line">{{ log }}</div>
109
+ </div>
110
+ </el-card>
111
+ </div>
112
+ </template>
113
+
114
+ <script>
115
+ import QuillEditor from './index.vue';
116
+
117
+ const SAMPLE_WITH_TABLE = `<h2>富文本编辑器示例</h2>
118
+ <p>这是一个 <strong>Quill</strong> 富文本编辑器示例,包含以下功能:</p>
119
+ <ul>
120
+ <li>基础格式:加粗、斜体、下划线、删除线</li>
121
+ <li>标题、段落、引用、列表</li>
122
+ <li>字号、颜色、对齐、缩进</li>
123
+ <li>图片(支持 base64 内联)</li>
124
+ <li>表格(quill-table-better)</li>
125
+ </ul>
126
+ <table>
127
+ <thead>
128
+ <tr><th>姓名</th><th>年龄</th><th>城市</th></tr>
129
+ </thead>
130
+ <tbody>
131
+ <tr><td>张三</td><td>28</td><td>北京</td></tr>
132
+ <tr><td>李四</td><td>32</td><td>上海</td></tr>
133
+ </tbody>
134
+ </table>
135
+ <p>试着编辑上方内容,查看下方 <code>HTML 源码</code> 输出。</p>`;
136
+
137
+ const SIMPLE_SAMPLE = '<p>这是一个<strong>精简</strong>示例,可在上方编辑触发事件。</p>';
138
+
139
+ export default {
140
+ name: 'QuillEditorDemo',
141
+ components: { QuillEditor },
142
+ data() {
143
+ return {
144
+ versionTip:
145
+ '基于 Quill 2 + quill-table-better,支持表格 / 图片 / 撤销重做,工具栏已中文化。',
146
+ // 卡片① 预设切换
147
+ presetMode: 'default',
148
+ presetContent: SAMPLE_WITH_TABLE,
149
+ // 卡片② 基础编辑器 + 源码联动
150
+ content1: SAMPLE_WITH_TABLE,
151
+ source1: SAMPLE_WITH_TABLE,
152
+ // 卡片③ 只读 / 禁用
153
+ content2: SAMPLE_WITH_TABLE,
154
+ content3: SAMPLE_WITH_TABLE,
155
+ // 卡片④ 自定义工具栏
156
+ content4: '<p>自定义工具栏示例:<strong>加粗</strong>、<em>斜体</em>、列表。</p>',
157
+ customToolbar: [
158
+ ['bold', 'italic'],
159
+ [{ list: 'ordered' }, { list: 'bullet' }],
160
+ ['link'],
161
+ ['clean'],
162
+ ],
163
+ // 卡片⑤ ref 方法
164
+ content5: '<p>点下方按钮调用组件方法(getHtml / getText / clear / focus)。</p>',
165
+ methodOutput: '',
166
+ // 卡片⑥ 事件监听
167
+ content6: SIMPLE_SAMPLE,
168
+ eventLogs: [],
169
+ };
170
+ },
171
+ watch: {
172
+ // 编辑器1 内容变化时,实时把源码同步到下方文本框
173
+ content1(val) {
174
+ this.source1 = val;
175
+ },
176
+ },
177
+ methods: {
178
+ onReady(quill) {
179
+ this.versionTip = `基于 Quill ${quill.version} + quill-table-better,支持表格 / 图片 / 撤销重做,工具栏已中文化。`;
180
+ },
181
+ // 卡片② 源码 → 编辑器1(整体写回)
182
+ applySource() {
183
+ this.content1 = this.source1;
184
+ if (this.$message) this.$message.success('已写回编辑器1');
185
+ },
186
+ // 卡片② 编辑器1 → 源码(手动刷新)
187
+ refreshSource() {
188
+ this.source1 = this.content1;
189
+ },
190
+ // 卡片⑤ ref 方法
191
+ callGetHtml() {
192
+ this.methodOutput = this.$refs.refDemo.getHtml();
193
+ },
194
+ callGetText() {
195
+ this.methodOutput = this.$refs.refDemo.getText();
196
+ },
197
+ callClear() {
198
+ this.$refs.refDemo.clear();
199
+ this.methodOutput = '(已清空)';
200
+ },
201
+ callFocus() {
202
+ this.$refs.refDemo.focus();
203
+ },
204
+ // 卡片⑥ 事件
205
+ onEvtFocus() {
206
+ this.pushLog('focus 获得焦点');
207
+ },
208
+ onEvtBlur() {
209
+ this.pushLog('blur 失去焦点');
210
+ },
211
+ onEvtChange(html) {
212
+ this.pushLog(`change 内容长度 ${html.length}`);
213
+ },
214
+ pushLog(text) {
215
+ const t = new Date().toLocaleTimeString();
216
+ this.eventLogs.unshift(`[${t}] ${text}`);
217
+ if (this.eventLogs.length > 20) this.eventLogs.splice(20);
218
+ },
219
+ },
220
+ };
221
+ </script>
222
+
223
+ <style scoped>
224
+ .quill-demo {
225
+ padding: 20px;
226
+ }
227
+
228
+ .demo-alert {
229
+ margin-bottom: 16px;
230
+ }
231
+
232
+ .demo-card {
233
+ margin-bottom: 16px;
234
+ }
235
+
236
+ .demo-card__header {
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: space-between;
240
+ }
241
+
242
+ .demo-card__title {
243
+ font-size: 15px;
244
+ font-weight: 600;
245
+ color: #303133;
246
+ }
247
+
248
+ .demo-card__subtitle {
249
+ display: block;
250
+ margin: 8px 0;
251
+ font-size: 13px;
252
+ color: #606266;
253
+ }
254
+
255
+ .demo-tip {
256
+ margin: 8px 0;
257
+ font-size: 12px;
258
+ line-height: 1.6;
259
+ color: #909399;
260
+ }
261
+
262
+ .demo-tip code,
263
+ .demo-card code {
264
+ padding: 1px 4px;
265
+ border-radius: 3px;
266
+ background: #f5f7fa;
267
+ color: #c7254e;
268
+ font-family: Consolas, 'Courier New', monospace;
269
+ }
270
+
271
+ .source-head {
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: space-between;
275
+ margin: 12px 0 8px;
276
+ }
277
+
278
+ .source-box >>> .el-textarea__inner {
279
+ font-family: Consolas, 'Courier New', monospace;
280
+ font-size: 12px;
281
+ }
282
+
283
+ .btn-row {
284
+ margin: 12px 0;
285
+ }
286
+
287
+ .log-panel {
288
+ margin-top: 12px;
289
+ max-height: 160px;
290
+ padding: 8px 12px;
291
+ overflow: auto;
292
+ border: 1px solid #ebeef5;
293
+ border-radius: 4px;
294
+ background: #f5f7fa;
295
+ font-family: Consolas, 'Courier New', monospace;
296
+ font-size: 12px;
297
+ }
298
+
299
+ .log-line {
300
+ line-height: 1.8;
301
+ color: #475669;
302
+ }
303
+
304
+ .log-empty {
305
+ color: #909399;
306
+ }
307
+ </style>