vue2 vue3 各传值汇总

序:

vue最常见的,容易为难新手的,应该就是组件间的传参的,所以本次笔记就记录下传参,顺带也记录下vue2吧

一、vue3

1、父传子

父组件atherTitle,fatherMoney,fatherWifi,thisIsEmpty等都是传过去给子组件的

<template>
<el-row class="mb-4">
	<el-button type="danger">props.vue传递父组件的参数到子组件,子组件用defineProps接收,fatherTitle和fatherMoney参数</el-button>
</el-row>
 
<!--写在父组件的子组件-->
<Son :fatherTitle="xxxxx" :fatherMoney="money" :fatherWifi="wifi" :thisIsEmpty="myEmptyStr" :fatherArr="myArr"></Son>
</template>
 
<script lang="ts" setup>
import { ref,reactive,watch,watchEffect } from 'vue'
import Son from "./son.vue"//引入子组件
 
const  xxxxx = ref("-----这是父组件的标题-----")
const money = ref(9999999999)
const wifi = reactive({pwd:222,name:"fffff"})
const myEmptyStr = ref("")
const myArr = reactive([{code:666,msg:"success"},{code:555,msg:"fail"}])
</script>

子组件接收defineProps() 接收父组件传递过来的参数,defineProps在setup语法糖可以直接使用,不需要import

<template>
    <el-row class="mb-4">
        <el-button type="success">
            son.vue:{
   
   {sonTitle}}-------{
   
   {fatherTitle}}-----{
   
   {fatherMoney}}
    	</el-button>
        <el-button type="success">{
   
   {fatherWifi}}--{
   
   {fatherWifi.pwd}}--{
   
   {fatherWifi.name}}</el-button>
        <el-button type="danger">
            父传递的空字符串:{
   
   {myEmptyStr}}
    	</el-button>
    </el-row>
    <el-row class="mb-4">
      <el-button type="primary" v-for="(item,index) in fatherArr" :key="index">
          {
   
   {item}},{
   
   {item.code}}
      </el-button>
    </el-row>
 
</template>
<script lang="ts" setup>
import { ref,reactive} from 'vue'
const sonTitle = "This is  son title"
//接收父组件传过来的值,需要注意defineProps只能在setup语法糖里面使用,不需要import引入
const yyyy = defineProps({
	fatherTitle:{
		type:String,//类型字符串
		default:'当前Child.vue的默认值'//如果没有传递msg参数,默认值是这个
	},
	fatherMoney:{
		type:Number,//类型字符串
		default:0//如果没有传递msg参数,默认值是这个
	},
	fatherWifi:{
		type:Object,//类型字符串
		default:{id:999}//如果没有传递msg参数,默认值是这个
	},
	myEmptyStr:{
		type:String,
		default:"myEmptyStr默认值为空字符串"
	},
	fatherArr:{
		type:Object,//类型字符串
		//default:[]//如果没有传递msg参数,默认值是这个
	},
})
 
console.log(yyyy.fatherArr)
console.log("-------这是子组件---------")
console.log(yyyy.fatherWifi)
console.log(yyyy.fatherTitle)
 
</script>

TS 特有的默认值方式

withDefaults是个函数也是无须引入开箱即用接受一个props函数第二个参数是一个对象设置默认值

type Props = {
    title?: string,
    data?: number[]
}
withDefaults(defineProps<Props>(), {
    title: "张三",
    data: () => [1, 2, 3]
})

2、子传父

子组件

<script lang="ts" setup>
import { ref,reactive} from 'vue'
 
//子组件调用父组件的方法,
//父组件的调用子组件的地方写上@onMySonFunc="fatherFunc"
const myEmit = defineEmits(["onMySonFunc"])//这样就调用到父组件的fatherFunc方法了
 
//传递参数: "调用父组件的方法"和666666
myEmit("onMySonFunc","调用父组件的方法",666666)


//如果用了ts可以这样两种方式
const emit = defineEmits<{
   (e: "onMySonFunc", name: string): void
   (e: "on-click", name: string): void
}>()
</script>

父组件@onMySonFunc=“funcToSon”,这样上面的子组件就能调用到父组件的funcToSon()方法了

<template>
<!--子组件调用父组件的funcToSon()方法-->
<Son  @onMySonFunc="funcToSon"></Son>
</template>
 
<script lang="ts" setup>
import { ref,reactive} from 'vue'
import Son from "./son.vue"//引入子组件
 
const funcToSon = (name:any,id:number)=>{
	console.log("子组件调用了父组件的funcToSon()方法",id)
	return {message:name}
}
</script>

3、隔代传

父组件provide传递参数到其他子孙组件

<script lang="ts" setup>
import { provide } from 'vue'
provide('test001', "987654321")
//provide传递test001的参数,值是987654321到子孙节点
</script>

儿子组件用inject接收父组件传递过来的参数

<script lang="ts" setup>
import {inject} from "vue"
 
//儿子组件用inject接收父组件传递过来的参数
const provideFatherStr = inject('thisFromGrandFather')
</script>

孙子组件也可以用inject接收父组件传递过来的参数

<script lang="ts" setup>
import {inject} from "vue"
 
//孙子组件用inject接收它爷爷组件传递过来的参数
const provideFatherStr = inject('thisFromGrandFather')
</script>

4、第三库(mitt || tiny-emitter

mitt 使用举例:

// eventBus.js
import mitt from 'mitt';

const emitter = mitt();

export default emitter;
// a.js
import emitter from './utils/eventBus'

emitter.emit('panda', {
    
    name: 'lokka', age: 2})
emitter.emit('flamingo', {
    
    name: 'disy', age: 1})
// b.js
import emitter from './utils/eventBus'
// 逐个监听
—————————————————————————————————————————
emitter.on('panda', (val) => {
    
    
	console.log(val)
})

emitter.on('flamingo', (val) => {
    
    
	console.log(val)
})

// 取消监听
funtion onFoo() {
    
    }
emitter.on('foo', onFoo)
emitter.off('foo', onFoo)
—————————————————————————————————————————
// 监听多个
emitter.on('*', (type, val) => {
    
    
	console.log(type, val)
})

// 取消监听多个
emitter.all.clear()

封装瀑布流组件

父组件:

<template>
    <waterFallVue :list="list"></waterFallVue>
</template>
 
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import waterFallVue from './components/water-fall.vue';
const list = [
    {
        height: 300,
        background: 'red'
    },
    {
        height: 400,
        background: 'pink'
    },
    {
        height: 500,
        background: 'blue'
    },
    {
        height: 200,
        background: 'green'
    },
    {
        height: 300,
        background: 'gray'
    },
    {
        height: 400,
        background: '#CC00FF'
    },
    {
        height: 200,
        background: 'black'
    },
    {
        height: 100,
        background: '#996666'
    },
    {
        height: 500,
        background: 'skyblue'
    },
    {
        height: 300,
        background: '#993366'
    },
    {
        height: 100,
        background: '#33FF33'
    },
    {
        height: 400,
        background: 'skyblue'
    },
    {
        height: 200,
        background: '#6633CC'
    },
    {
        height: 300,
        background: '#666699'
    },
    {
        height: 300,
        background: '#66CCFF'
    },
    {
        height: 300,
        background: 'skyblue'
    },
    {
        height: 200,
        background: '#CC3366'
    },
    {
        height: 200,
        background: '#CC9966'
    },
    {
        height: 200,
        background: '#FF00FF'
    },
    {
        height: 500,
        background: '#990000'
    },
    {
        height: 400,
        background: 'red'
    },
    {
        height: 100,
        background: '#999966'
    },
    {
        height: 200,
        background: '#CCCC66'
    },
    {
        height: 300,
        background: '#FF33FF'
    },
    {
        height: 400,
        background: '#FFFF66'
    },
    {
        height: 200,
        background: 'red'
    },
    {
        height: 100,
        background: 'skyblue'
    },
    {
        height: 200,
        background: '#33CC00'
    },
    {
        height: 300,
        background: '#330033'
    },
    {
        height: 100,
        background: '#0066CC'
    },
    {
        height: 200,
        background: 'skyblue'
    },
    {
        height: 100,
        background: '#006666'
    },
    {
        height: 200,
        background: 'yellow'
    },
    {
        height: 300,
        background: 'yellow'
    },
    {
        height: 100,
        background: '#33CCFF'
    },
    {
        height: 400,
        background: 'yellow'
    },
    {
        height: 400,
        background: 'yellow'
    },
    {
        height: 200,
        background: '#33FF00'
    },
    {
        height: 300,
        background: 'yellow'
    },
    {
        height: 100,
        background: 'green'
    }
 
]
</script>
 
<style  lang='less'>
#app,
html,
body {
    height: 100%;
}
 
* {
    padding: 0;
    margin: 0;
}
</style>

子组件:

<template>
    <div class="wraps">
        <div :style="{height:item.height+'px',background:item.background,top:item.top+'px',left:item.left + 'px'}"
            v-for="item in waterList" class="items"></div>
    </div>
</template>
 
<script setup lang='ts'>
import { ref, reactive, onMounted } from 'vue'
const props = defineProps<{
    list: any[]
}>()
const waterList = reactive<any[]>([])
const init = () => {
    const heightList: any[] = []
    const width = 130;
    const x = document.body.clientWidth
    const column = Math.floor(x / width)
 
    for (let i = 0; i < props.list.length; i++) {
        if (i < column) {
            props.list[i].top = 10;
            props.list[i].left = i * width;
            heightList.push(props.list[i].height + 10)
            waterList.push(props.list[i])
        } else {
            let current = heightList[0]
            let index = 0;
            heightList.forEach((h, inx) => {
                if (current > h) {
                    current = h;
                    index = inx;
                }
            })
            console.log(current,'c')
            props.list[i].top = (current + 20);
            console.log(props.list[i].top,'top',i)
            props.list[i].left = index * width;
            heightList[index] =  (heightList[index] + props.list[i].height + 20);
            waterList.push(props.list[i])
        
        }
    }
    console.log(props.list)
}
 
onMounted(() => {
    window.onresize = () => init()
    init()
})
 
</script>
 
<style scoped lang='less'>
.wraps {
    position: relative;
     height: 100%;
    .items {
        position: absolute;
        width: 120px;
    }
}
</style>

在这里插入图片描述

二、vue2

1、父传子

父组件

<template>
    <div class="wrap">
        <div>我是Father组件</div>
        <Son
          str="我是字符串"
          isPublished
          :num=5
          :obj="{cont:'我是一个对象'}"
          :func="()=>{this.hello()}"
          :arr="arr"></Son>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Father",
        data(){
            return{
                arr:[1,2,3]
            }
        },
        methods:{
            hello(){
                console.log("hello world!")
            }
        },
        components:{  Son  }
    }
</script>

子组件

<template>
    <div>我是Son组件</div>
</template>
<script>
    export default {
        name: "Son",
        props:{//props列表
            arr:Array,//定义参数类型
            num:Number,
            isPublished: Boolean,
            str:String,
            str2:{
                type:String,
                default:"我是默认字符串"//定义参数默认值
            },
            func:{
                type:Function,
                required:false//定义参数是否必须值
            },
            obj:{
                type: Object,
                required:false
            }
        },
        created() {
            console.log(this.str);//我是字符串
            console.log(this.str2);//我是默认字符串
            console.log(this.num);//5
            console.log(this.isPublished);//true
            console.log(this.func);//hello(){console.log("hello world!");}
            console.log(this.arr);//[1,2,3]
            console.log(this.obj);//{cont:'我是一个对象'}
            this.func();//hello world!
        }
    }
</script>

2、子传父

2.1、$emit

父组件

<template>
    <div class="wrap">
        <div>我是Father组件</div>
        <Son @func="speak" ></Son>
    </div>
</template>

<script>
    import Son from './Son'
    export default {
        name: "Father",
        methods:{
           speak(msg){
               console.log(msg);//我是子组件发送的消息!
           }
        },
        components:{
            Son
        }
    }
</script>

子组件

<template>
    <div>
        <div>我是Son组件</div>
    </div>
</template>

<script>
    export default {
        name: "Son",
        mounted() {
             //func 是绑定的事件名
            this.$emit('func',"我是子组件发送的消息!");
        }
    }
</script>

2.2、直接传

父组件

<template>
  <div class="parent">
    <child :fatherMethod='fatherMethod'></child>// 父组件把方法传入子组件中,在子组件里直接调用这个方法
  </div>
</template>

<script>
    import child from '../base/child'
    
    export default {
        methods:{
            fatherMethod() {
                alert('我是父组件的know方法');
            }
        },
        components:{
            child
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

子组件

<template>
  <div class="child" @click='childClick'>
  </div>
</template>

<script>

    export default {
        props:{
            fatherMethod: {
                type: Function,
                default: null
            }
        },
        methods:{
            childClick(){
                this.fatherMethod()
        }
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .child{
    width: 100px;
    height: 100px;
    background-color: blue;
  }
</style>

2.3、$refs

父组件

<template>
    <div class="wrap">
        <div>我是Father组件</div>
        <!-- ref绑定节点 -->
        <Son ref="son">
          <!-- @click.stop  阻止冒泡 -->
          <button @click.stop="UGG">按钮</button>
        </Son>
    </div>
</template>

<script>
    import Son from './Son'
    export default {
        name: "Father",
        mounted(){
          //获取节点
            this.$refs['son'].$on('func',(msg)=>{
                console.log(msg);
            })
        },
        methods:{
            UGG(){
              //调用节点里的方法
              this.$refs['son'].show()
            }
        },
        components:{
            Son
        }
    }
</script>

子组件

<template>
    <div>
        <div>我是Son组件</div>
        <button @click="$emit('func','我是子组件传递的消息1!')">Send1</button>
        <button @click="sendMsg">Send2</button>
        <!-- 插槽 -->
        <slot></slot>
    </div>
</template>

<script>
    export default {
        name: "Son",
        methods:{
            sendMsg(){
                //func 是绑定的事件名
                this.$emit('func','我是子组件传递的消息2!');
            },
            show(){
                console.log('显示')
            }
        }
    }
</script>

2.4、$parent

$root$parent 都能够实现访问父组件的属性和方法,两者的区别在于,如果存在多级子组件,通过parent 访问得到的是它最近一级的父组件,通过root 访问得到的是根父组件(App.vue) 所以存在组件嵌套的情况下 不要使用 $root

父组件

<template>
  <div class="parent">
    <child></child>// ref 作用在组件上 指向的是组件的实例 实例上的方法都可以调用
  </div>
</template>

<script>
    import child from '../base/child'
    
    export default {
        data() { // 组件的data必须是函数
          return {
            msg:'父组件数据测试'
          }
        },
        methods:{
          fatherMethod() {
            alert('我是父组件的方法')
          }
        },
        components:{
            child
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

子组件

<template>
  <div class="child" @click='childClick'>
  </div>
</template>

<script>

    export default {
        data() {
            return {
                msg: '我是子组件传递过来的数据'
            }
        },
        methods:{
            childClick(){
                this.$parent.fatherMethod()
                console.log(this.$parent.msg)
        }
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .child{
    width: 100px;
    height: 100px;
    background-color: blue;
  }
</style>

3、兄弟传值

在main.js种挂载全局EventBus

Vue.prototype.$EventBus = new Vue()

A组件

<template>
    <div class="wrap">
        <div>我是组件A</div>
        <button @click="sendMsg">发送</button>
    </div>
</template>

<script>
    export default {
        name: "A",
        methods:{
            sendMsg(){
               this.$EventBus.$emit('sendMsg',"这是组件A发送的消息!")
            }
        }
    }
</script>

B组件

<template>
    <div>
        <div>我是组件B</div>
    </div>
</template>

<script>
    export default {
        name: "B",
        mounted(){
            this.$EventBus.$on('sendMsg',(msg)=>{
                console.log(msg);//这是组件A发送的消息!
            })
        },
    }
</script>

4、隔代传值( provide / inject

provide是父级组件需要传递给子孙组件的属性/方法

//选项一
provide: {
    
    
  content: 'hello world'
}

//选项二
provide(){
    
    
  return {
    
    
    content: 'hello world'
  }
}

inject是子孙组件用来接收父级组件属性/方法

//选项一
inject: ['content']

//选项二
inject: {
    
    
  content: 'content'
}

//选项三
inject: {
    
    
  content: {
    
    
    from:'content',
    default:'hello world'
  }
}

a.vue

<template>
    <div>
        <span>{
   
   {a}}</span>
        <aa></aa>
    </div>
</template>

<script>
    import aa from './aa';
    
    export default {
        data(){
            return {
                a: "我是a组件中数据"
            }
        },
        provide() {
            return {
                msg: this.a
            }
        },
        components: {
            aa
        }
    }
</script>

aa.vue

<template>
    <div>
    </div>
</template>

<script>
    export default {
        inject: ['msg'],
        created() {
            console.log(this.msg); // 我是a组件中数据
        }
    }
</script>

5、跨级($attrs / $listeners

  • ** a t t r s : ∗ ∗ 包含了父作用域中不被 p r o p 所识别 ( 且获取 ) 的特性绑定 ( c l a s s 和 s t y l e 除外 ) 。当一个组件没有声明任何 p r o p 时,这里会包含所有父作用域的绑定 ( c l a s s 和 s t y l e 除外 ) ,并且可以通过 v − b i n d = " attrs:**包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=" attrs包含了父作用域中不被prop所识别(且获取)的特性绑定(classstyle除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(classstyle除外),并且可以通过vbind="attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。
  • ** l i s t e n e r s : ∗ ∗ 包含了父作用域中的 ( 不含 . n a t i v e 修饰器的 ) v − o n 事件监听器。它可以通过 v − o n = " listeners:**包含了父作用域中的 (不含 .native修饰器的) v-on 事件监听器。它可以通过 v-on=" listeners包含了父作用域中的(不含.native修饰器的)von事件监听器。它可以通过von="listeners" 传入内部组件

父组件

<template>
    <div>
        <span>{
   
   {name}}</span>
        <span>{
   
   {price}}</span>
        <aa
        :name="name"
        :price="price"
        :size="size"
        ></aa>
    </div>
</template>

<script>
    import aa from './aa';   
    export default {
        data(){
            return {
                name: "可乐",
                price: 3,
                size: "500ml"
            }
        },
        provide() {
            return {
                msg: this.a
            }
        },
        components: {
            aa
        }
    }
</script>

子组件aa.vue

<template>
    <div>
        <span>{
   
   {name}}</span>
        <aaa v-bind="$attrs"></aaa>
    </div>
</template>

<script>
    import aaa from './aaa';    
    export default {
        props: ['name'],
        components: {
            aaa
        }
    }
</script>

子组件aaa.vue

<template>
    <div>
    </div>
</template>

<script>    
    export default {
        created() {
            console.log(this.$attrs); // {price: 3, size: "500ml"}
        }
    }
</script>

总结: $attrs 与 l i s t e n e r s 是两个对象, listeners 是两个对象, listeners是两个对象,attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。

6、插件传值

安装 pubsub-js 插件: npm i pubsub-js -s 可实现全局参数传递

  • publishSync 同步发送消息
  • publish 同步发送消息
  • subscribe 订阅消息
  • unsubscribe 卸载特定订阅
  • clearAllSubscriptions 清除所有订阅

组件A

<template>
    <div class="wrap">
        <div>我是组件A</div>
        <button @click="sendMsg">发送</button>
    </div>
</template>

<script>
    import  pubsub from 'pubsub-js'
    export default {
        name: "A",
        methods:{
            sendMsg(){
                //publishSync  同步发送消息
                pubsub.publishSync("sendMsg","这是A组件发布的消息!");
            }
        }
    }
</script>

组件B

<template>
    <div>
        <div>我是组件B</div>
    </div>
</template>

<script>
    import pubsub from 'pubsub-js'
    export default {
        name: "B",
        mounted(){
            //subscribe    订阅消息
            pubsub.subscribe("sendMsg",(e,msg)=>{
                console.log(e,msg);//sendMsg 这是A组件发布的消息!
            })
        },
    }
</script>

7、路由传值

7.1、页面直接传参

<router-link :to="{ path:'./attachment',query:{order_id: task.ORDERID}}">
    <mt-button type="primary" size="small">查看附件</mt-button>
</router-link>

7.2、通过方法传递参数

methods: {
    
    
    society() {
    
    
        //console.log('society');
        this.$router.push({
    
    
            name:'society',
            query:{
    
    value:1}
        })
},

7.3、接值

methods:{
    
    
    loadData:function(){
    
    
    	this.id = this.$route.query.order_id;
    	axios.get("http://testqywx.origimed.com:18082/weixin-qy/order/Order/userOrderFilesList.json?usercode=sysadmin&orderId="+this.id)
    	.then(response=>this.tasks=response.data.reason);
    }
},

哎呀,累了,没想到总结下来,还不少,暂时先这么多吧,回头有了再更新~

猜你喜欢

转载自blog.csdn.net/MoXinXueWEB/article/details/127098394
今日推荐