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>

 

posted @ 2020-03-17 14:32  dirgo  阅读(1734)  评论(0编辑  收藏  举报