zoukankan      html  css  js  c++  java
  • 最新的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>

     这里几种方法,改天我再整理一下,写成大家都容易理解的。目前看有点绕!时间久了,自己都感觉奇怪!

  • 相关阅读:
    P4568 [JLOI2011]飞行路线(分层图)
    打地鼠游戏(贪心)
    雷神领域(并查集真是个好东西)并查集+流氓dp
    P2934 [USACO09JAN]安全出行
    P2893 [USACO08FEB]修路
    P2894 [USACO08FEB]酒店Hotel
    P4145 上帝造题的七分钟2 / 花神游历各国
    P2579 [ZJOI2005]沼泽鳄鱼(邻接矩阵,快速幂)
    P2905 [USACO08OPEN]农场危机Crisis on the Farm(简单dp+麻烦“回溯”)
    day 2 上午 挂饰 背包
  • 原文地址:https://www.cnblogs.com/xiaohuasan/p/15720539.html
Copyright © 2011-2022 走看看