【问题标题】:How to make a template variable non-reactive in Vue如何在 Vue 中使模板变量不响应
【发布时间】:2019-03-21 11:36:00
【问题描述】:

我有一个编辑表单,其中的变量保存在 data() 中。我不想更新编辑页面的标题,但我想保持输入和数据之间数据的 v-model 同步。使标题在 h1 标签中无反应的最简单方法是什么?为此,游先生必须有所准备..

<template>
    <div>
        <h1>{{ title }}</h1>
        <input v-model="title">
    </div>
</template>

<script>    
export default {
    data: {
        title: 'Initial value'      
    }
}
</script>

【问题讨论】:

  • 我想看看是否还有其他方法,比如 v-static 指令。引用相同数据变量的标题。即编辑 {{ title }}
  • 如果你想要单向绑定,使用:value="title"而不是v-model
  • @RoyJ 但这仅适用于具有属性“值”的输入?怎么样输出,例如上面的标题标签。
  • 在下面查看我的答案。

标签: vue.js


【解决方案1】:

Vue docsdata() 中的返回对象上推荐Object.freeze() 以禁用对属性的反应性:

data() {
  return Object.freeze({ title: 'Initial value' })
}

但需要注意的是,它会冻结 所有 属性(看起来无法使用此方法仅冻结某些属性),并且 使用v-model 会导致控制台错误 (Cannot assign to read only property)

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',
  data() { 
    return Object.freeze({
      message: 'Hello Vue.js!',
    })
  }
})
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="app">
  <p>{{ message }}</p>
  <input v-model="message"> <!-- XXX: Cannot use v-model with frozen property. This will cause a console error. -->
</div>

或者,您可以通过redefining itwriteable: false 任意删除任何可配置数据属性的反应性:

methods: {
  removeReactivity() {
    Object.defineProperty(this, 'title', {value: null, writeable: false});
  }
}

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',
  data() { 
    return {
      message: 'Hello Vue.js!',
    }
  },
  methods: {
    removeReactivity() {
      Object.defineProperty(this, 'message', {value: null, writeable: false});
    }
  }
})
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="app">
  <p>{{ message }}</p>
  <input v-model="message">

  <div>
    <button @click="removeReactivity">
      Remove reactivity for <code>message</code>
    </button>
  </div>
</div>

【讨论】:

  • 你的第一个 sn-p 会产生错误,因为 Vue 试图写入冻结的对象。
  • 是的。事先在说明中说明了这一警告。
【解决方案2】:

如果您不希望输入更改数据项的值,请使用value 绑定它而不是双向v-model。然后它只是作为输入的初始化器。

如果您想拥有两个值,一个不会改变,一个会从另一个初始化,您需要有两个数据项。不变的可以是prop with a default value。另一个是data 成员,如果您使用data 函数,它可以将自身初始化为prop 值。

new Vue({
  el: '#app',
  props: {
    initTitle: {
      default: 'Initial value'
    }
  },
  data() {
    return {
      title: this.initTitle
    };
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <h1>{{ initTitle }}</h1>
  <input v-model="title">
  <div>Title is "{{title}}"</div>
</div>

您也可以使用鲜为人知的$options 属性将您的标题定义为一种内部常量而不是道具。我对这是一个好的设计方法还是一个太奇怪的步骤感到复杂。

new Vue({
  el: '#app',
  initTitle: 'Initial value',
  data() {
    return {
      title: this.$options.initTitle
    };
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <h1>{{ $options.initTitle }}</h1>
  <input v-model="title">
  <div>Title is "{{title}}"</div>
</div>

【讨论】:

  • 也考虑过并通过使用 $options 来解决这样的事情。最终在 init 上定义了一个单独的数据变量。
【解决方案3】:

如果您不想为input 创建单独的变量,您可以使用v-once 指令来达到您的目的。来自docs

只渲染元素和组件一次。在随后的重新渲染中, 元素/组件及其所有子元素将被视为静态 内容并跳过。

new Vue({
  el: "#app",
  data: {
    title: "initial value"
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>

<div id="app">
  <input v-model="title">
  <p>Reactive title: {{ title }}</p>
  <p v-once>Static title: {{ title }}</p>
</div>

【讨论】:

    【解决方案4】:

    the contents of this blog向后工作...

    看起来,当您为 Vue 创建对象时,它会使用响应式 getter 和 setter 创建属性。如果您随后将属性附加到该对象的带外,则它不会获得反应能力,但仍可作为值访问。

    这应该可以为您解决:

    <template>
        <div>
            <h1>{{ titleContainer.value }}</h1>
            <input v-model="title">
        </div>
    </template>
    
    <script>    
    export default {
        data: {
            titleContainer: {}
        }
    }
    titleContainer.value = "Initial Value"
    </script>
    

    【讨论】:

      【解决方案5】:

      由于 Vue 会自动为所有对象属性注入反应式 getter 和 setter,因此没有简单的方法可以解决您的问题。您可以在变量上使用 Object.freeze() 来消除反应性,但它​​会应用于整个对象本身,这不是您想要的。

      我从 vue 中创建了一个名为 vue-for-babylonians 的分支来限制反应性,甚至允许某些对象属性是反应性的。看看here

      有了它,你可以告诉 Vue 不要让任何存储在 vue 或 vuex 中的对象成为响应式的。您还可以告诉 Vue 使对象属性的某些子集具有响应性。您会发现性能得到了显着提升,并且您可以像在 vue/vuex 中一样享受存储和传递大型对象的便利。

      【讨论】:

        猜你喜欢
        • 2019-06-24
        • 2022-11-11
        • 2021-04-04
        • 2019-08-28
        • 2019-01-22
        • 2021-02-28
        • 2017-02-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多