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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM