zoukankan      html  css  js  c++  java
  • vue 试图改变子组件props 属性值时,控制台报错解决方案

    报错信息:Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-...

    出错原因:

    单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

    额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

    解决方案:

    使用$emit('事件名称',参数)方法,将子组件数据作为参数抛出给组件的事件(事件名称可自定义),在父级组件监听这个事件,并且在父组件写一个方法作为事件处理函数,则子组件抛出的数据将作为方法的第一个参数传入,然后在此方法内改变prop参数值即可.

    实际上数据流向:子组件----$emit触发事件抛出数据---->父组件----监听事件改变prop---->子组件

    代码:

    子组件:

     1 <template>
     2   <div>
     3     <!-- 将v-model 拆解为v-bind:value="value"  v-on:input="value => $emit('input', value)" 实现封装组件的v-model双向绑定-->
     4     <Tabs type="card" closable @on-tab-remove="handleTabRemove" v-bind:value="value"  v-on:input="value => $emit('input', value)" @on-click="handleTabClick">
     5       <TabPane v-for="(tab,ind) in tabs" :index="ind+1" ref="tabPanes" :key="tab.component" :name="tab.component" :label="tab.component" :v-if="tab.display" >
     6         <Content :style="mainContent" ref="main-cotent">
     7           <router-view />
     8         </Content>
     9       </TabPane>
    10       <Button @click="closeAll" size="small" slot="extra">关闭全部</Button>
    11     </Tabs>
    12   </div>
    13 </template>
    14 
    15 <script>
    16 export default {
    17   name: 'i_tabs',
    18   props: {
    19     value:{
    20 
    21     },//父组件v-model透传来的value数据,实现双向绑定
    22     tab_prop: {
    23       type: Object
    24     }
    25 
    26   },
    27   data() {
    28     return {
    29       tabs: this.tab_prop.tabs,
    30       mainContent: {
    31         'padding-left': '14px',
    32         'padding-right': '14px',
    33         background: '#fff',
    34         height: '1000px'
    35       }
    36     };
    37   },
    38   created() {
    39 
    40   },
    41   methods: {
    42     handleTabsAdd() {
    43 
    44     },
    45     handleTabRemove(name) {
    46       console.log('----关闭标签方法,参数name=', name);
    47 
    48       console.log("----关闭tab前tabs:",this.tabs);
    49       var thiz = this;
    50       var index;
    51       this.tabs.forEach(function(element) {
    52         if (element.component == name) {
    53           index = thiz.tabs.indexOf(element);
    54           element.display = false;
    55         }
    56       });
    57       //如果关闭的是最左侧标签,则激活右侧标签,否则激活左侧标签
    58       if(this.tabs.length > 1){
    59         let name ="";
    60         if(index == 0){
    61           name = this.tabs[index+1].component;
    62 
    63         }else{
    64           name = this.tabs[index-1].component;
    65         }
    66         console.log('----tab组件,关闭后---激活标签==', name);
    67          this.$emit('change-active-tab-name', name);//向父组件传递数据:借助vue内建的$emit方法触发change-active-tab-name事件,抛出参数name
    68          this.$router.push(name);
    69       }
    70       this.tabs.splice(index, 1);
    71       console.log("----关闭tab后tabs:",this.tabs);
    72 
    73     },
    74     closeAll() {},
    75     handleTabClick(name){
    76       console.log("---handleTabClick方法,标签name==",name)
    77       this.$router.push(name);
    78     }
    79 
    80   },
    81   mounted() {
    82 
    83   },
    84   watch: {
    85     '$route' (newRoute) {
    86       console.log("------监控路由变化,参数newRoute==",newRoute)
    87       console.log('----tab组件,---激活标签==', this.value);
    88     //   const { name, query, params, meta } = newRoute
    89     }
    90   },
    91   components: {}
    92 };
    93 </script>
    94 
    95 <style></style>

    父组件:

     1 <template>
     2   <div class="index">
     3     <Layout :style="{ padding: '0 24px 24px', background: '#fff' }">
     4           <i_tabs ref="navTabs" :tab_prop="tab_prop" v-model="activeName" @change-active-tab-name="changeActiveName"></i_tabs>
     5         </Layout>
     6 </div>
     7 </template>
     8 
     9 <script>
    10 import i_tabs from '@/components/template/i_tabs/i_tabs.vue';
    11 export default {
    12   name: 'index',
    13   props: {},
    14   data() {
    15     return {
    16       user: {},
    17       mainContent: {
    18         'padding-left': '14px',
    19         'padding-right': '14px',
    20         background: '#fff',
    21         height: '1000px'
    22       },
    23       activeName:"",
    24       tab_prop: {
    25         tabs: []
    26       }
    27     };
    28   },
    29 methods: {
    30     changeActiveName(name){//父组件事件处理函数,改变传入子组件的prop属性值
    31       this.activeName = name;
    32     }
    33 }
    34 ,
    35   components: {
    36     i_tabs
    37   }
    38 };
    39 </script>
    40 <style></style>
  • 相关阅读:
    vscode Git提交
    安装 nrm
    vue+element ui项目总结点(六)table编辑当前行、删除当前行、新增、合计操作
    Filebrowser安装教程
    vue数据处理:把数组处理成适用于tree组件的数据
    WC2016模拟Divisor
    对拍模板
    题解(5031. 【NOI2017模拟3.27】B)(数论,组合数学)
    Codeforces #657 Div2C choosing flowers
    关于一个大菜鸡的记录
  • 原文地址:https://www.cnblogs.com/dirgo/p/12510541.html
Copyright © 2011-2022 走看看