最新的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>

这样子组件可以动态生成无数个也不会错乱了。

 

posted @ 2021-12-22 18:00  剧里局外  阅读(1058)  评论(0编辑  收藏  举报