Skip to content

Commit f55d907

Browse files
committed
fix(reactivity): correctly trigger content update if prop changes (fixes #188)
1 parent f19a1d7 commit f55d907

File tree

1 file changed

+39
-12
lines changed

1 file changed

+39
-12
lines changed

packages/vue-quill/src/components/QuillEditor.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ import {
1616
PropType,
1717
watch,
1818
ref,
19+
shallowRef,
1920
h,
2021
} from 'vue'
2122
import { toolbarOptions, ToolbarOptions } from './options'
2223

23-
export type Module = { name: string; module: any; options?: object }
24+
export type Module = { name: string; module: unknown; options?: object }
2425

2526
export const QuillEditor = defineComponent({
2627
name: 'QuillEditor',
@@ -161,7 +162,7 @@ export const QuillEditor = defineComponent({
161162
}
162163
if (props.modules) {
163164
const modules = (() => {
164-
const modulesOption: { [key: string]: any } = {}
165+
const modulesOption: { [key: string]: unknown } = {}
165166
if (Array.isArray(props.modules)) {
166167
for (const module of props.modules) {
167168
modulesOption[module.name] = module.options ?? {}
@@ -185,13 +186,32 @@ export const QuillEditor = defineComponent({
185186
)
186187
}
187188

189+
const internalModel = shallowRef(props.content)
190+
const internalModelEquals = (against: Delta | String | undefined) => {
191+
if (typeof internalModel.value === typeof against) {
192+
if (against === internalModel.value) {
193+
return true
194+
}
195+
if (against instanceof Delta && internalModel.value instanceof Delta) {
196+
return internalModel.value.diff(against).length() > 0
197+
}
198+
}
199+
return false
200+
}
188201
const handleTextChange: TextChangeHandler = (
189202
delta: Delta,
190203
oldContents: Delta,
191204
source: Sources
192205
) => {
193-
// Update v-model:content when text changes
194-
ctx.emit('update:content', getContents())
206+
const content = getContents()
207+
if (content) {
208+
// Quill should never be null at this point, so content should not be undefined but let's make ts happy
209+
internalModel.value = content
210+
// Update v-model:content when text changes
211+
if (!internalModelEquals(props.content)) {
212+
ctx.emit('update:content', internalModel.value)
213+
}
214+
}
195215
ctx.emit('textChange', { delta, oldContents, source })
196216
}
197217

@@ -202,7 +222,7 @@ export const QuillEditor = defineComponent({
202222
source: Sources
203223
) => {
204224
// Set isEditorFocus if quill.hasFocus()
205-
isEditorFocus.value = quill?.hasFocus() ? true : false
225+
isEditorFocus.value = !!quill?.hasFocus()
206226
ctx.emit('selectionChange', { range, oldRange, source })
207227
}
208228

@@ -306,13 +326,20 @@ export const QuillEditor = defineComponent({
306326
})
307327
}
308328

309-
// watch(
310-
// () => props.content,
311-
// (newContent, oldContents) => {
312-
// if (!quill || !newContent || newContent === oldContents) return
313-
// setContents(newContent)
314-
// }
315-
// )
329+
watch(
330+
() => props.content,
331+
(newContent) => {
332+
if (!quill || !newContent || internalModelEquals(newContent)) return
333+
334+
internalModel.value = newContent
335+
// Restore the selection and cursor position after updating the content
336+
const selection = quill.getSelection()
337+
if (selection) {
338+
nextTick(() => quill?.setSelection(selection))
339+
}
340+
setContents(newContent)
341+
}
342+
)
316343

317344
watch(
318345
() => props.enable,

0 commit comments

Comments
 (0)