index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <div class="editor">
  3. <quill-editor
  4. v-model:content="content"
  5. contentType="html"
  6. @textChange="(e) => $emit('update:modelValue', content)"
  7. :options="options"
  8. :style="styles"
  9. />
  10. </div>
  11. </template>
  12. <script setup>
  13. import { QuillEditor } from '@vueup/vue-quill';
  14. import '@vueup/vue-quill/dist/vue-quill.snow.css';
  15. const props = defineProps({
  16. /* 编辑器的内容 */
  17. modelValue: {
  18. type: String,
  19. },
  20. /* 高度 */
  21. height: {
  22. type: Number,
  23. default: null,
  24. },
  25. /* 最小高度 */
  26. minHeight: {
  27. type: Number,
  28. default: null,
  29. },
  30. /* 只读 */
  31. readOnly: {
  32. type: Boolean,
  33. default: false,
  34. },
  35. });
  36. const options = ref({
  37. theme: "snow",
  38. bounds: document.body,
  39. debug: "warn",
  40. modules: {
  41. // 工具栏配置
  42. toolbar: [
  43. ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
  44. ["blockquote", "code-block"], // 引用 代码块
  45. [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
  46. [{ indent: "-1" }, { indent: "+1" }], // 缩进
  47. [{ size: ["small", false, "large", "huge"] }], // 字体大小
  48. [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  49. [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
  50. [{ align: [] }], // 对齐方式
  51. ["clean"], // 清除文本格式
  52. ["link", "image", "video"] // 链接、图片、视频
  53. ],
  54. },
  55. placeholder: '请输入内容',
  56. readOnly: props.readOnly
  57. });
  58. const styles = computed(() => {
  59. let style = {};
  60. if (props.minHeight) {
  61. style.minHeight = `${props.minHeight}px`;
  62. }
  63. if (props.height) {
  64. style.height = `${props.height}px`;
  65. }
  66. return style;
  67. })
  68. const content = ref("");
  69. watch(() => props.modelValue, (v) => {
  70. if (v !== content.value) {
  71. content.value = v === undefined ? "<p></p>" : v;
  72. }
  73. }, { immediate: true });
  74. </script>
  75. <style>
  76. .editor, .ql-toolbar {
  77. white-space: pre-wrap !important;
  78. line-height: normal !important;
  79. }
  80. .quill-img {
  81. display: none;
  82. }
  83. .ql-snow .ql-tooltip[data-mode="link"]::before {
  84. content: "请输入链接地址:";
  85. }
  86. .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  87. border-right: 0px;
  88. content: "保存";
  89. padding-right: 0px;
  90. }
  91. .ql-snow .ql-tooltip[data-mode="video"]::before {
  92. content: "请输入视频地址:";
  93. }
  94. .ql-snow .ql-picker.ql-size .ql-picker-label::before,
  95. .ql-snow .ql-picker.ql-size .ql-picker-item::before {
  96. content: "14px";
  97. }
  98. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
  99. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  100. content: "10px";
  101. }
  102. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
  103. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  104. content: "18px";
  105. }
  106. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
  107. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  108. content: "32px";
  109. }
  110. .ql-snow .ql-picker.ql-header .ql-picker-label::before,
  111. .ql-snow .ql-picker.ql-header .ql-picker-item::before {
  112. content: "文本";
  113. }
  114. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
  115. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  116. content: "标题1";
  117. }
  118. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
  119. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  120. content: "标题2";
  121. }
  122. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
  123. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  124. content: "标题3";
  125. }
  126. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
  127. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  128. content: "标题4";
  129. }
  130. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
  131. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  132. content: "标题5";
  133. }
  134. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
  135. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  136. content: "标题6";
  137. }
  138. .ql-snow .ql-picker.ql-font .ql-picker-label::before,
  139. .ql-snow .ql-picker.ql-font .ql-picker-item::before {
  140. content: "标准字体";
  141. }
  142. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
  143. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
  144. content: "衬线字体";
  145. }
  146. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
  147. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
  148. content: "等宽字体";
  149. }
  150. </style>