最新的vue3練習和vue3父組件向子組件傳值


需要實現的功能是,點擊列表(子組件),修改父組件的值,並改子組件變背景顏色。

效果圖

這里用四種方法實現,應該還有第五種,第六種。

如果有更好的方式,歡迎大家留言提供。

 頁面

最上級頁面

<template>
    <div class="box">
        <div>列表項目</div>
        <MyList :list="dataList"></MyList>
    </div>
</template>

<script>
    import MyList from '../components/MyList.vue'
    import {
        reactive
    } from "vue"
    export default {
        name: "index",
        components: {
            MyList
        },
        setup() {
            let dataList = reactive([{
                    name: 'aaa',
                    age: 15,
                    isSelected:false
                }, {
                 name: 'bbb',
                    age: 20,
                    isSelected:false
                },
                {
                    name: 'ccc',
                    age: 10,
                    isSelected:false
                },
                {
                    name: 'ddd',
                    age: 50,
                    isSelected:false
             },
                {
                    name: 'eee',
                    age: 88,
                    isSelected:false
                }
         ])
            return {
                dataList
            }
        }
    }
</script>

<style>
    .box {
        padding: 50px 20px;
    }
</style>

 

父級頁面

第一種方法是在元素上直接修改 

 <MyListItem  v-for="(item,index) in list2" :listItem=item @selected="item.isSelected=$event.target.checked;item.name='大哥哥'" ></MyListItem> 

這個表示賦值,直接修改了

item.isSelected=$event.target.checked;item.name='大哥哥'

  參考,幫助理解

<template>
 <div>
  <input type="text" v-model="newValue">
 </div>
</template>
<script>
export default {
 props:{
  value:{
   type:String,
   default:''
  }
 },
 computed:{
  newValue:{
   get:function(){
    return this.value
   },
   set:function(value){
    this.$emit('input',value)//為了理解,看作是子組件中的方法
   }
  }
 }
}
</script>

  方便理解v-modelv-model = "msg" 可以翻譯為:

:value="msg"
@input="msg=$events"//看作是父組件中調用

 

第二種是在setup里寫方法改就如下面的頁面

<template>
    <!-- <MyListItem  v-for="(item,index) in list2" :listItem=item @selected="item.isSelected=$event.target.checked;item.name='大哥哥'" ></MyListItem> -->
    <MyListItem v-for="(item,index) in list2" :listItem=item @selected="mySelected"></MyListItem>
</template>

<script>
    import MyListItem from "./MyListItem.vue"
    import {
        toRefs,
        ref
    } from 'vue'
    export default {
        name: "MyList",
        props: ["list"],
        components: {
            MyListItem
        },
        setup(props, cxt) {
            const list2 = ref(props.list)//獲取從父級傳來的值
            //console.log(list2,"ddd")
            //let num={ref(list2).value}
            //console.log(num[0].name) //aaa
            function mySelected(value, name) {//接受子組件傳來的值,並改變數據
                list2.value.map((item) => {//遍歷尋找當前點擊過的item項
                    if (item.name == name) {//相同表示選中了
                        item.isSelected = value.target.checked; //修改子項屬性
                    }
                })
            }
            return {
                list2,
                mySelected
            }

        }
    }
</script>

<style>
</style>

子組件頁面

第一種是 直接在元素上自定義方法,這里傳了一個事件參數和一個item.name屬性

  <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="$emit('selected',$event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div>

 這里把方法定義到元素上,而不是在setup里

<template>
    <div class="box-item">
     <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="$emit('selected',$event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div>
    </div>
</template>

<script>
import { ref } from "vue";
    export default{
        name:"MyListItem",
        props:["listItem"],
        setup(props,cxt){
            const listItem=ref(props.listItem)
            return{
                listItem
            }
        }
    }
</script>

<style>
    .box-item{
        padding: 10px;
    }
    .box-active{
        background: red;
    }
    .box-unactive{
        background: white;
    }
</style>

第二種也是在setup里寫法,傳遞參數

頁面

 

<template>
    <div class="box-item">
     <!-- <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="$emit('selected',$event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div> -->
    <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="sonClick($event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div>
        
    </div>
</template>

<script>
import { ref } from "vue";
    export default{
        name:"MyListItem",
        props:["listItem"],
        emits:["selected"],
        setup(props,cxt){
            const listItem=ref(props.listItem)//接受父級傳來的參數
            function sonClick(e,name){
                cxt.emit('selected',e,name);
            }
            return{
                listItem,
                sonClick
            }
        }
    }
</script>

<style>
    .box-item{
        padding: 10px;
    }
    .box-active{
        background: red;
    }
    .box-unactive{
        background: white;
    }
</style>

剛剛接觸vue3,如果發現代碼有問題,歡迎大家指出來。

第三種方法

把子組件調用的方法作為屬性,然后通過改變屬性,去改變值,不知道這樣描述對不對。

父組件

<template>
    <!-- <MyListItem  v-for="(item,index) in list2" :listItem=item @selected="item.isSelected=$event.target.checked;item.name='大哥哥'" ></MyListItem> -->
    <MyListItem v-for="(item,index) in list2" :listItem="item" :selected="changeChecked" :numIndex="index"></MyListItem>
</template>
<script>
    import MyListItem from "./MyListItem.vue"
    import {
        toRefs,
        ref
    } from 'vue'
    export default {
        name: "MyList",
        props: {
            list: {
                type: Array //數據
            }
        },

        components: {
            MyListItem
        },
        setup(props, cxt) {
            const list2 = ref(props.list) //獲取從父級傳來的值
            function changeChecked(num) {
                let item = list2.value[num] //獲得選中的項
                item.isSelected = !item.isSelected //修改選中狀態
            }
            return {
                list2,
                changeChecked
            }

        }
    }
</script>

<style>
</style>

 

子組件

<template>
    <div class="box-item">
        <!-- <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="$emit('selected',$event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div> -->
        <div :class='listItem.isSelected==true?"box-active":"box-unactive"'> <input type="checkbox"
                @change="selectedItem" />
            {{listItem.name}}--{{listItem.age}}
        </div>

    </div>
</template>

<script>
    import {
        ref
    } from "vue";
    export default {
        name: "MyListItem",
        props: {
            listItem: {
                listItem: Object
            },
            selected: {
                type: Function //方法作為屬性傳過去
            },
            numIndex: {
                type: Number //索引ID號屬性
            }
        },
        setup(props, cxt) {
            const listItem = ref(props.listItem) //接受父級傳來的參數
            //點擊方法然后調用屬性去改變值
            function selectedItem() {
                props.selected(props.numIndex); //調用父級方法和屬性
            }
            return {
                listItem,
                selectedItem
            }
        }
    }
</script>

<style>
    .box-item {
        padding: 10px;
    }

    .box-active {
        background: red;
    }

    .box-unactive {
        background: white;
    }
</style>

 第四種方法使用  

provide 和 inject

父組件

<template>
    <!-- <MyListItem  v-for="(item,index) in list2" :listItem=item @selected="item.isSelected=$event.target.checked;item.name='大哥哥'" ></MyListItem> -->
    <MyListItem v-for="(item,index) in list2" :listItem=item @selected="mySelected"></MyListItem>
</template>

<script>
    import MyListItem from "./MyListItem.vue"
    import {
        toRefs,
        ref,
        provide
    } from 'vue'
    export default {
        name: "MyList",
        props: ["list"],
        components: {
            MyListItem
        },
        setup(props, cxt) {
            const list2 = ref(props.list)//獲取從父級傳來的值
            //console.log(list2,"ddd")
            //let num={ref(list2).value}
            //console.log(num[0].name) //aaa
            function mySelected(value, name) {//接受子組件傳來的值,並改變數據
                list2.value.map((item) => {
                    if (item.name == name) {
                        item.isSelected = value.target.checked; //修改子項屬性
                    }
                })
            };
            
        //第四種方法
        const xuanzhong=(value,name)=>{ //匿名方法
                list2.value.map((item) => {
                    if (item.name == name) {
                        item.isSelected = value.target.checked; //修改子項屬性
                    }
                })
             }
             provide('xuanzhong',xuanzhong);//傳遞數據
            return {
                list2,
                mySelected
            }

        }
    }
</script>

<style>
</style>

子組件

<template>
    <div class="box-item">
     <!-- <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="$emit('selected',$event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div> -->
    <div :class='listItem.isSelected==true?"box-active":"box-unactive"' > <input type="checkbox" @change="xuanzhong($event,listItem.name)" /> {{listItem.name}}--{{listItem.age}} </div>
        
    </div>
</template>

<script>
import { ref,inject } from "vue";
    export default{
        name:"MyListItem",
        props:["listItem"],
        emits:["selected"],
        setup(props,cxt){
            const listItem=(props.listItem)//接受父級傳來的參數
            function sonClick(e,name){
                cxt.emit('selected',e,name);
            }
             const xuanzhong = inject('xuanzhong') //接受父級方法
            return{
                listItem,
                sonClick,
                xuanzhong
            }
        }
    }
</script>

<style>
    .box-item{
        padding: 10px;
    }
    .box-active{
        background: red;
    }
    .box-unactive{
        background: white;
    }
</style>

 這里幾種方法,改天我再整理一下,寫成大家都容易理解的。目前看有點繞!時間久了,自己都感覺奇怪!

 

子組件 

<template>
    <view>
        <view>
            <u--input v-model="newDate" border="none" :placeholder="chyPlaceholder" @focus="selectShow">
            </u--input>
        </view>
        <u-calendar :show="chyDateShow" :mode="mode" @confirm="confirm" :monthNum="chyMonthNum" :minDate="minDate" >
        </u-calendar>
    </view>
</template>

<script>
    const d = new Date()
    const year = d.getFullYear()
    let month = d.getMonth() - 1
    month = month < 10 ? `0${month}` : month
    const date = d.getDate()
    import props from './props.js'
    export default {
        name: 'chy-date-select',
        data() {
            return {
                newDate: "",
                mode: 'single',
                minDate: `${year}-${month}-${date + 10}`, //設置最小值范圍
                chyDateShow:false,
            }
        },
        mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
        methods: {
            selectShow() {
                //this.$emit("openShow",true);
                this.chyDateShow=true;
            },
            confirm(e) {
                this.chyDateShow = false;
                //console.log(e, "console.log(e)");
                this.newDate = e[0];
                this.$emit("selectDateValue", this.newDate)
            },
        },
    }
</script>

<style>
</style>

父組件里方法調用賦值 太完美了

@selectDateValue="(chyValue)=>{formCustomer.contractDate=chyValue}"

 <chy-date-select chyPlaceholder="簽約日期" :selectDate="formCustomer.contractDate" @selectDateValue="(chyValue)=>{formCustomer.contractDate=chyValue}"></chy-date-select>

這樣子組件可以動態生成無數個也不會錯亂了。

 


免責聲明!

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



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