最新的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>
第四种方法使用
<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>
这样子组件可以动态生成无数个也不会错乱了。