RichTextEditor.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <template>
  2. <FlexCol>
  3. <view class="richtext-preview-box" @click="() => !disabled && !readonly ? edit() : preview()">
  4. <Parse v-if="modelValue" :content="modelValue" containerStyle="max-height:400px" />
  5. <Text v-else color="text.second">{{placeholder}}</Text>
  6. <view v-if="modelValue" class="richtext-preview-mask" :style="maskStyle" />
  7. </view>
  8. <FlexRow :gap="20" justify="flex-end" align="center">
  9. <Button v-if="!disabled" icon="browse" text="预览" size="small" @click="preview" />
  10. <Button v-if="!disabled && !readonly" icon="edit" text="编辑" size="small" @click="edit" type="primary" />
  11. <Text v-if="maxLength > 0" :text="`${modelValue?.length || 0}/${maxLength} 字`" fontConfig="subText" textAlign="right" />
  12. </FlexRow>
  13. </FlexCol>
  14. </template>
  15. <script setup lang="ts">
  16. import { onPageShow } from '@dcloudio/uni-app';
  17. import { navTo } from '@/components/utils/PageAction';
  18. import Parse from '@/components/display/parse/Parse.vue';
  19. import Button from '@/components/basic/Button.vue';
  20. import Text from '@/components/basic/Text.vue';
  21. import FlexCol from '@/components/layout/FlexCol.vue';
  22. import FlexRow from '@/components/layout/FlexRow.vue';
  23. import { propGetThemeVar, useTheme } from '@/components/theme/ThemeDefine';
  24. import { computed } from 'vue';
  25. const props = defineProps({
  26. modelValue: {
  27. type: String,
  28. default: null
  29. },
  30. maxLength: {
  31. type: Number,
  32. default: -1,
  33. },
  34. placeholder: {
  35. type: String,
  36. default: '未编写内容,点击编写',
  37. },
  38. disabled: {
  39. type: Boolean,
  40. default: false,
  41. },
  42. readonly: {
  43. type: Boolean,
  44. default: false,
  45. },
  46. maskColor: {
  47. type: String,
  48. default: () => propGetThemeVar('RichTextEditorMaskColor', 'white'),
  49. }
  50. })
  51. const emit = defineEmits(['update:modelValue'])
  52. const theme = useTheme();
  53. let editorOpened = false;
  54. const maskStyle = computed(() => ({
  55. height: theme.resolveThemeSize('RichTextEditorMaskHeight', 100),
  56. background: `linear-gradient(0deg, ${theme.resolveThemeColor(props.maskColor)} 0%, transparent 100%)`,
  57. }));
  58. function preview() {
  59. uni.setStorage({
  60. key: 'editorContent',
  61. data: props.modelValue,
  62. success: () => navTo('/pages/editor/preview'),
  63. })
  64. }
  65. function edit() {
  66. editorOpened = true;
  67. uni.setStorage({
  68. key: 'editorMaxLength',
  69. data: props.maxLength,
  70. })
  71. uni.setStorage({
  72. key: 'editorContent',
  73. data: props.modelValue,
  74. success: () => navTo('/pages/editor/editor'),
  75. })
  76. }
  77. onPageShow(() => {
  78. if (editorOpened) {
  79. editorOpened = false;
  80. uni.getStorage({
  81. key: 'editorContent',
  82. success: (success) => emit('update:modelValue', success.data),
  83. })
  84. }
  85. })
  86. </script>
  87. <style lang="scss" scoped>
  88. .richtext-preview-box {
  89. position: relative;
  90. flex: 1;
  91. min-height: 400rpx;
  92. margin-bottom: 15rpx;
  93. .richtext-preview-mask {
  94. position: absolute;
  95. bottom: -1px;
  96. left: 0;
  97. width: 100%;
  98. }
  99. }
  100. </style>