Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v-model绑定值类型异常 #71

Closed
3 of 5 tasks
maoxuner opened this issue Aug 30, 2023 · 12 comments
Closed
3 of 5 tasks

v-model绑定值类型异常 #71

maoxuner opened this issue Aug 30, 2023 · 12 comments

Comments

@maoxuner
Copy link

Before you start, please make sure to:

  • Read the doc
  • Have tried the latest version
  • Search to see if your issue already exists
  • Look for / ask questions on Stack Overflow
  • Reproduce the bug in incognito/private mode to avoid interference from browser extensions

Link to minimal reproduction

https://cloydlau.github.io/demo/json-editor-vue.html

Steps to reproduce

打开默认示例,不做其他任何操作

  1. 直接点击“Print binding value in the Console”,输出的值是对象类型
  2. 切换到text模式,编辑任意内容,再点击“Print binding value in the Console”,输出的值是字符类型
  3. 切换到tree模式,不做任何操作,“Print binding value in the Console”,输出的值是字符类型
  4. tree模式,编辑任意内容,再点击“Print binding value in the Console”,输出的值是对象类型

绑定值需要是对象类型,输出值也应该一直是对象类型才对

What is expected?

输入输出类型应该保持一致,要么同为字符串,要么同为对象

What is actually happening?

输入输出类型不一致

System Info

浏览器名字	Chrome
浏览器版本	116.0.0.0
系统平台	Linux
原始UA信息	Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36

Package Manager

npm

Any additional comments?

No response

@cloydlau
Copy link
Owner

这个问题其实就是切换模式和更新绑定值是两个不同的操作,切换模式时是没有更新绑定值的。关于这个事情我之前给 svelte-jsoneditor 提过 PR:josdejong/svelte-jsoneditor#166

@cloydlau cloydlau closed this as not planned Won't fix, can't repro, duplicate, stale Aug 31, 2023
@maoxuner
Copy link
Author

抱歉,我没仔细看svelte-jsoneditor 与 json-editor-vue 中绑定值的差异这个说明

@cloydlau
Copy link
Owner

没事,方便的话给 json-editor-vue 点一个 star,谢谢

@thatsgolden
Copy link

抱歉,我没仔细看svelte-jsoneditor 与 json-editor-vue 中绑定值的差异这个说明

image

这里描述为 “所见即所得” 其实有点不合适,在 text 模式中,用户看到的仍然是格式化的 json 树结构,但实际上,绑定值已经变成 string 了,而非 object,是反直觉的。

image

@thatsgolden
Copy link

另外,这里的编辑模式绑定值,不知是否能理解成在上面那个 pr 中,大家提到的预期行为,即 v-model:tree 绑定值始终更新为 object 对象,即使是在 text 模式下粘贴的内容。但是经过实验,实际并非如此,与 v-model 的行为一致,在 text 模式下粘贴 json 对象,绑定值类型变成了 string。

image

@cloydlau
Copy link
Owner

@thatsgolden 你好,
所见即所得是指绑定值是 json 本身,而没有嵌套层级的意思,至于值类型是另外一回事了。
前文已经提过,你的疑惑我之前也有,我也给作者提了 pr,详见:josdejong/svelte-jsoneditor#166
建议你看完全文,一两句话说不清楚,也评论下你的看法和方案,看看 svelte-jsoneditor 作者怎么说。

@thatsgolden
Copy link

@thatsgolden 你好, 所见即所得是指绑定值是 json 本身,而没有嵌套层级的意思,至于值类型是另外一回事了。 前文已经提过,你的疑惑我之前也有,我也给作者提了 pr,详见:josdejong/svelte-jsoneditor#166 建议你看完全文,一两句话说不清楚,也评论下你的看法和方案,看看 svelte-jsoneditor 作者怎么说。

我明白作者的意思。我是想说,我在使用您的组件时,发现您这里说了一句所见即所得,误以为无需注意不同编辑模式下产生的值类型变化问题,所见即所得,在我看来还有一层隐藏的意思,那就是绑定值的类型不应被组件所修改,使用者传递给您 object 类型,但是 text 模式编辑后,变成了 string 类型,此时与使用原始组件是一样,仍需要自行做一层处理。但是文档中的那句话,让人产生了误解

@thatsgolden
Copy link

我在与后端数据交互时,原本是直接把绑定值 JSON.stringify 后作为 post Data 传递的,今天在 text 模式下粘贴了一个 JSON 对象,然后提交发现 data 被两次 JSON.stringify 了,就挺疑惑的,才知道 text 和 json 下是有区别的,我之前以为两种模式只是编辑模式(界面风格)的不同,没想到还会影响绑定值的类型

@cloydlau
Copy link
Owner

cloydlau commented Nov 20, 2023

对于你的使用场景,可以选择锁定模式。

svelte-jsoneditor:
绑定值:{ text: xxx, json: xxx }
用户看到的部分:xxx

json-editor-vue:
绑定值:xxx
用户看到的部分:xxx

这就是所见即所得的意思,与值类型无关,值类型无法通过人眼“看出来”,比如 true,就人眼观察来说是无法知道是 boolean 还是 string 的,又比如 1,也无法知道是 number 还是 string,所以我认为这么描述没啥问题。

模式与值类型无关这一点,目前为止已经超过三个人跟我提过了,说明确实是反直觉的,有更好的方案建议在 josdejong/svelte-jsoneditor#166 中进行补充,大家头脑风暴一下。

@cloydlau
Copy link
Owner

由于本问题很热门,在文档中更新了以下内容:

如果你想确保在 text 模式中总是得到 “parsed JSON”:

Caution

对于大型 JSON 文档性能不佳

createApp(App)
  .use(JsonEditorVue, {
    mode: 'text',
    mainMenuBar: false,
    onChange(updatedContent) {
      if (updatedContent.text) {
        try {
          updatedContent.json = JSON.parse(updatedContent.text)
        }
        catch {}
        updatedContent.text = undefined
      }
    },
  })
  .mount('#app')

或不使用 try...catch:

<JsonEditorVue
  ref="jsonEditorVueRef"
  mode="text"
  :main-menu-bar="false"
  :on-change="(updatedContent) => {
    if (updatedContent.text) {
      if (!jsonEditorVueRef.jsonEditor.validate()) {
        updatedContent.json = JSON.parse(updatedContent.text)
      }
      updatedContent.text = undefined
    }
  }"
/>

CC @maoxuner @thatsgolden

@maoxuner
Copy link
Author

maoxuner commented Apr 12, 2024

@cloydlau 感谢告知,我是在JsonEditorVue的基础上做了一层包裹组件来处理值的编码和解析的,方法跟这里差不多。代码还能再优化优化,比如使用jsonEditor.validate(),使用计算属性来设置content并处理input事件

<template>
  <!-- eslint-disable-next-line vue/attribute-hyphenation -->
  <json-editor-vue :content="content" :onChange="onChange" v-bind="$attrs" />
</template>

<script>
import JsonEditorVue from 'json-editor-vue'

export default {
  name: 'JsonEditor',
  components: {
    JsonEditorVue
  },
  props: {
    value: {
      type: null,
      default: null
    }
  },
  data() {
    return {
      content: this.decoder(this.value)
    }
  },
  watch: {
    value(newValue, oldValue) {
      if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
        this.content = this.decoder(newValue)
      }
    }
  },
  methods: {
    decoder(value) {
      return {
        json: JSON.parse(JSON.stringify(value))
      }
    },
    encoder(value) {
      return value
    },
    onChange(updatedContent, previousContent, { contentErrors, patchResult }) {
      this.content = updatedContent
      if (Object.prototype.hasOwnProperty.call(updatedContent, 'json')) {
        this.onInput(updatedContent.json)
      } else {
        try {
          this.onInput(JSON.parse(updatedContent.text))
        } catch {
          //
        }
      }
    },
    onInput(value) {
      this.$emit('input', this.encoder(value))
    }
  }
}
</script>

PS:已经转行转岗,没有信心在IT行业了,后会有期。

@cloydlau
Copy link
Owner

cloydlau commented Apr 14, 2024

看到了 wangEditor 暂停维护的文章:https://juejin.cn/post/7272735633458413602
行情确实很差,开源不易、坚持维护更不易。

在 v0.14.0 中大家可以更加优雅地实现这一点:

Caution

  • 对于大型 JSON 文档性能不佳
  • 请根据你的 JSON 大小来调整 debounce 的值
  • 输入值无效时会输出空
<JsonEditorVue mode="text" :stringified="false" :debounce="1000" />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants