index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. theme: 'snow'
  58. });
  59. const styles = computed(() => {
  60. let style = {};
  61. if (props.minHeight) {
  62. style.minHeight = `${props.minHeight}px`;
  63. }
  64. if (props.height) {
  65. style.height = `${props.height}px`;
  66. }
  67. return style;
  68. })
  69. const content = ref("");
  70. watch(() => props.modelValue, (v) => {
  71. if (v !== content) {
  72. content.value = v === undefined ? "<p></p>" : v;
  73. }
  74. }, { immediate: true });
  75. </script>
  76. <style>
  77. .editor, .ql-toolbar {
  78. white-space: pre-wrap !important;
  79. line-height: normal !important;
  80. }
  81. .quill-img {
  82. display: none;
  83. }
  84. .ql-snow .ql-tooltip[data-mode="link"]::before {
  85. content: "请输入链接地址:";
  86. }
  87. .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  88. border-right: 0px;
  89. content: "保存";
  90. padding-right: 0px;
  91. }
  92. .ql-snow .ql-tooltip[data-mode="video"]::before {
  93. content: "请输入视频地址:";
  94. }
  95. .ql-snow .ql-picker.ql-size .ql-picker-label::before,
  96. .ql-snow .ql-picker.ql-size .ql-picker-item::before {
  97. content: "14px";
  98. }
  99. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
  100. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  101. content: "10px";
  102. }
  103. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
  104. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  105. content: "18px";
  106. }
  107. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
  108. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  109. content: "32px";
  110. }
  111. .ql-snow .ql-picker.ql-header .ql-picker-label::before,
  112. .ql-snow .ql-picker.ql-header .ql-picker-item::before {
  113. content: "文本";
  114. }
  115. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
  116. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  117. content: "标题1";
  118. }
  119. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
  120. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  121. content: "标题2";
  122. }
  123. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
  124. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  125. content: "标题3";
  126. }
  127. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
  128. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  129. content: "标题4";
  130. }
  131. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
  132. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  133. content: "标题5";
  134. }
  135. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
  136. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  137. content: "标题6";
  138. }
  139. .ql-snow .ql-picker.ql-font .ql-picker-label::before,
  140. .ql-snow .ql-picker.ql-font .ql-picker-item::before {
  141. content: "标准字体";
  142. }
  143. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
  144. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
  145. content: "衬线字体";
  146. }
  147. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
  148. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
  149. content: "等宽字体";
  150. }
  151. </style>