"$attrs 是只读的","$listeners 是只读的","避免直接改变一个 prop"

Posted

技术标签:

【中文标题】"$attrs 是只读的","$listeners 是只读的","避免直接改变一个 prop"【英文标题】:"$attrs is readonly","$listeners is readonly","Avoid mutating a prop directly" 【发布时间】:2018-09-10 04:03:37 【问题描述】:

我是 Vue 的新手。我正在尝试开发一个聊天应用程序,其中朋友列表将显示在左侧菜单上,聊天框将显示在正文中。我正在使用 ajax 调用加载朋友列表并根据朋友 ID 路由到聊天框。这是代码示例。

<div class="chat-container clearfix" id="chat">
    <div class="people-list" id="people-list">
        <chatlist-component></chatlist-component>
    </div>

    <div class="chat">
       <router-view></router-view>
    </div>
</div> 

聊天列表组件将从服务器加载好友列表。这是我的 app.js 文件;

Vue.use(VueRouter)

const router = new VueRouter(
  routes,
  linkActiveClass: "active"
);


    import ChatComponent from './components/ChatComponent';
    const routes = [
       path: '/chat/:id/:name', component: ChatComponent , name: 'chat'
    ];
    Vue.component('chatlist-component', require('./components/ChatlistComponent.vue'));

    const app = new Vue(
        el: '#chat',
        router
    );

及聊天列表组件模板代码

<li class="clearfix" v-for="user in users">
                <img :src="baseUrl+'/img/default_image.jpeg'"  class="chat-avatar rounded-circle" />
                <router-link class="about" :to=" name: 'chat', params:  id: user.id, name:user.name ">
                    <div class="name">user.name</div>
                    <div class="status">
                        <i class="fa fa-circle online"></i> online
                    </div>
                </router-link>

            </li>

在我切换到另一个用户之前它工作正常。当我单击聊天列表组件中的任何路由器列表时,它可以正常工作,但会向控制台抛出以下错误。

app.js:19302 [Vue warn]: $attrs is readonly.

found in

---> <RouterLink>
       <ChatlistComponent> at resources/assets/js/components/ChatlistComponent.vue
         <Root>

app.js:19302 [Vue warn]: $listeners is readonly.

found in

---> <RouterLink>
       <ChatlistComponent> at resources/assets/js/components/ChatlistComponent.vue
         <Root>

app.js:19302 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "to"

提前致谢

【问题讨论】:

【参考方案1】:

首先,这些错误仅在非生产版本中出现,但它们表明应该在生产发布之前解决问题。

如果加载了多个 Vue 实例,则会显示 $attrs、$listeners 和其他警告。据我了解,这通常是由于以下原因之一:

它正在通过 webpack 加载/打包到包中,并且也在外部加载(不是通过 webpack) 它被你包含的东西加载(例如vuetify,vue-test-utils,vue-cli-electron-builder)一种方式和你的webpack配置另一种方式(例如绝对路径与相对路径,common.js与esm.js vue文件, runtime-only vue vs compiler+runtime vue)

如果您单击该行(在上面的输出中是 app.js:19302)并在消息发出的位置放置一个断点,您可以在堆栈回溯中查看模块列表以查看是否有超过列出了 Vue 的一条路径。例如,看下面的前三个模块有不同的路径(但都是 Vue 的一部分): 如果您看到 Vue 以两种或多种不同的方式出现,则表明加载了多个 Vue 实例。 Vue 只支持单个实例,如果加载多个实例,就会产生这些错误消息。

上面包含几个问题的链接,Vuetify 问题是我提交的问题。在那种情况下,Vuetify 需要 Vue 并且加载它的方式与我不同。通常修复方法是检查指定(或未指定)Vue 的 webpack 配置,并尝试使其与包含其他副本的方式相匹配(例如,绝对路径与相对路径,或打包与外部)。

【讨论】:

你也可以运行yarn why vue(如果使用yarn)来查看哪些包可能在复制vue。 这是刚刚添加的付费课程的新部分,但我会包含链接以防有人订阅。另外,值得注意的是,本课的主题是 $attrs 在 Vue 3 中已经完全改变。请参阅新文档和本课程关于从 2 迁移到 3,特别是本课,称为 The New $attrs:@987654325 @ 对我来说,问题正是你所说的,我从 index.html 文件中删除了额外的导入,错误消失了,它创建了 2 个实例。谢谢。 也看到了这个,但想补充一下,这是因为我在一个包中进行开发,并使用yarn link 在另一个应用程序中测试该包的实现。最初的包依赖于 Vue 2.x,我的应用程序也是如此。一旦我将包真正更新/导入到我的应用程序中,这就不成问题了。【参考方案2】:

将此添加到 vue.config.js,对我有用。

const path = require('path')

module.exports = 
  configureWebpack: 
    externals: 
      vue: 'Vue'
    
  

【讨论】:

这告诉 webpack 你想把它从捆绑过程中排除。所以做 import Vue from 'vue'; 不会做任何事情。这对你有用,因为你是从其他地方获得 vue,比如你的 html 中的脚本标签。【参考方案3】:

我遇到了同样的问题。对我来说,当我使用

安装本地模块时
yarn add ../somemodule --force

似乎这个命令将复制整个模块目录,包括 node_modules 子目录。这会导致相同版本的“vue”模块重复。在浏览器开发工具中,我可以看到模块的多个来源。

对我来说,解决方案是每次安装本地模块后手动删除 node_modules。

【讨论】:

这也是我使用npm install &lt;folder&gt;时的问题,例如npm install ../my-local-lib【参考方案4】:

就我而言,我是从一个不使用 VueCLI 的项目迁移而来的。在那个项目中,我从 CDN &lt;script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"&gt;&lt;/script&gt; 导入了 vue。在我的 Vue CLI 项目中,我已将整个 index.html 文件复制并粘贴到 Public 文件夹中。 Vue CLI 有自己的导入 vue 的方式,所以它们发生了冲突。我只是删除了脚本,问题就解决了。

【讨论】:

【参考方案5】:

这个错误发生在我身上,因为我在我的项目中使用了 Git 子模块并且我有以下文件夹:

./node_modules - 这是针对主要项目的。这些 node_modules 中安装了 vue。 ./my_git_submodules/vue_design_system/node_modules - 提供基本组件的设计系统(也使用 vue)。 这里也安装了Vue!!

所以因为两者:

./node_modules/vue./my_git_submodules/vue_design_system/node_modules/vue

存在,运行 npm run servevue-cli-service build 下面)构建了两个 Vue 实例。这是 一个非常讨厌的问题,因为它在某些情况下会破坏反应性 (即,您单击一个按钮,没有任何反应 - 您只是得到 $listeners 只读错误)

快速修复: 删除子文件夹(vue_design_system)中的 node_modules 并运行 npm run serve 对我有用。

长期修复: 您可能需要通过在 vue.config.js 中添加规则来使 Webpack 忽略嵌套的 node_modules 文件夹

【讨论】:

【参考方案6】:

我遇到了和上面一样的问题。我正在使用 git 子模块并且我使用过

yarn add ./submodule

不知何故,最终在 ./submodule 目录中出现了一个 node_modules 目录,这让一切变得混乱。

它正在加载两个 Vue 实例。

【讨论】:

【参考方案7】:

这也可能发生,因为您使用 npm link 来使用未发布的 vue 包。与@walnut_salami 的解释基本一致。

解决此问题的方法是移至 this way 以包含未发布的模块。

【讨论】:

【参考方案8】:

看起来好像有很多可能的答案。

我手动向节点文件夹添加了一个 npm 包,问题是缺少 npm i 命令。使用 install 命令后,一切正常。

【讨论】:

【参考方案9】:

在我的例子中,这个错误是在模块联合我的组件之后出现的。 我通过将组件接收器中的 vue 共享给组件供应商来解决它。 例如

webpack.config.js 
module.exports =  
   plugins: [
        
    new ModuleFederationPlugin(
      name: "dashboard",
      remotes: 
        web_common: "web_common@http://localhost:8081/remoteEntry.js"
      ,
      shared: 
        vue:  // this solved my issue.
          eager: true,
          singleton: true,
          requiredVersion: deps.vue
        ,
      
    ),
   ]


【讨论】:

以上是关于"$attrs 是只读的","$listeners 是只读的","避免直接改变一个 prop"的主要内容,如果未能解决你的问题,请参考以下文章

JQuery js如何判断标签指定属性是不是存在

关于jquery或js的attr方法,$("#img").attr(width:"这里想用百分比");

JQuery DatePicker 只读

jQuery .val() 与 .attr("值")

jquery .attr("value") 方法取到的值不对的问题

HTML如何禁止文本框输入