vue3(3.5版本以上)传值方式

结论

  1. props父传子
  2. defineEmits子传父
  3. mitt兄弟组件传参
  4. $attrs (爷孙)
  5. refs
  6. v-model(双向)
  7. provide/inject(多层)
  8. 路由传参
  9. vuex传参 (全局)
  10. pinia传参 (全局)
  11. 浏览器缓存 (全局)
  12. window (全局)
  13. app.config.globalProperties (全局)

一:父传子

defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
TestPage.vue 父组件

<template>
    <p>
    111
    <TestB :name="name"> 

    </TestB>
  </p>
  <p>父组件中的值:{{ name }}</p>
  <button @click="modify">点击</button>
</template>

<script lang="ts" setup>
import { ref } from "vue";
import TestB from '@/components/TestB.vue'
const name = ref('你好')
const modify = () => {
  name.value += '1'
}
</script>

testB.vue 子组件

<template>
  <div class="testContainer">

    <div>
      <span>{{ props.name }}</span>
    </div>
  </div>

</template>
<script setup>
import { watchEffect, reactive, ref, computed, defineProps, withDefaults } from "vue";
const props = defineProps(
  {
    name: {
      type: String,
      default: '默认值',
      required: false // 是否必传
    }
  }
)
// ts写法(3.4及以下版本)
//  const props = withDefaults(defineProps<{
//      name?: string // 是否必传
//  }>(), {
//      name: '默认值'
//  })
    
    // ts写法(3.5版本)
//  const { name= '默认值' } = defineProps<{
//      name?: string // 是否必传
//  }>()

watchEffect(() => {
// 在 3.5 之前仅运行一次
  // 在 3.5+ 版本中会在 "name" prop 改变时重新运行
  console.log(props)
})

</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

二:defineEmits子传父

testPage.vue父组件

<template>
  <div>
    这是父组件
    <TestB @addEvent = "handle"> 
    </TestB>
  </div>
  <p>子组件中的值:{{ childValue }}</p>
</template>

<script lang="ts" setup>
import { ref } from "vue";
import TestB from '@/components/TestB.vue'
const childValue = ref('')
const handle = (v) => {
  childValue.value = v
}
</script>

testB.vue 子组件

<template>
  <div class="testContainer">

    <div>
     <button @click="clickEvent">点击我</button>
    </div>
  </div>

</template>
<script setup>
import { watchEffect, reactive, ref, computed, defineProps, withDefaults } from "vue";
 const name = ref('你好吖')
 const emits = defineEmits(['addEvent'])

const clickEvent = () => {
  emits('addEvent', name.value)
}
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

三:兄弟组件传参(mitt)

testPage.vue父组件

<template>
  <div>
    这是父组件
    <TestB > 
    </TestB>
    <FancyButton> 
    </FancyButton>
  </div>
</template>

<script lang="ts" setup>
import TestB from '@/components/TestB.vue'
import FancyButton from '@/views/aboutPage/FancyButton.vue'
</script>
testB.vue (发射事件)
<template>
  <div class="testContainer">
    <div>
     <button @click="clickEvent">点击我</button>
    </div>
  </div>

</template>
<script setup>
import { watchEffect, reactive, ref, computed, defineProps, withDefaults,getCurrentInstance } from "vue";
import mitter from '@/utils/eventBus'

 const name = ref('你好吖')
 const {proxy } = getCurrentInstance()
const clickEvent = () => {
  console.log(name.value);
   // 方式一
  // mitter.emit('foo', { a: 'b' })
  // 方式二
  proxy.$bus.emit('test', { a: 'xxx' })
}
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>
FancyButton.vue (监听事件)

<template>
    <div class="fancy-btn">
        2222
    </div>
</template>
<script setup>
import {getCurrentInstance} from 'vue'

import mitter from '@/utils/eventBus'
const {proxy } = getCurrentInstance()

mitter.on('foo', (value)=>{
  console.log(value);
})
mitter.on('*', (type,data) => {
    console.log('Received in B:', type);
    console.log('Received in B:', data);
});

// 方式二监听
proxy.$bus.on('test', (value)=>{
  console.log(value);
})
</script>

采用全局挂载方式使用的时候记得在项目的main.js中提前挂载

import { createApp } from 'vue'

import mitt from "mitt"
const app = createApp(App)
app.config.globalProperties.$bus = new mitt()
app.mount('#app')

四:$attrs

实际上这是父传子的衍生,用于组件封装比较多
TestPage.vue父组件

<template>
  <div>
    这是父组件
    <TestB :id="id" :name="name"> 
    </TestB>
  </div>
</template>

<script lang="ts" setup>
import TestB from '@/components/TestB.vue'
import FancyButton from '@/views/aboutPage/FancyButton.vue'
const name = '你好,这是父组件';
const id =123
</script>

testB子组件

<template>
  <div class="testContainer">
    <div>
     <button @click="clickEvent">{{props.name}}</button>
    </div>
  </div>

</template>
<script setup>
import {useAttrs } from "vue";
const props = defineProps({
  name: {
    type: String
  }
})
 const myattrs = useAttrs()

 console.log(props,19);
 console.log(myattrs,20);// 可以看到这里面打印的是 props以外的属性
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

五:refs传参

引入一下ref,没啥好说的
testPage.vue父组件

<template>
  <div>
    这是父组件
    <TestB ref ="childRef"> 
    </TestB>
    <Button @click="btnClick">父组件按钮点击</Button>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import TestB from '@/components/TestB.vue'
const childRef = ref<InstanceType<typeof TestB>>(null)
const  btnClick = () => {
  childRef.value?.logEvent()
  console.log(childRef.value?.name,17)
}
</script>

testB.vue子组件

<template>
  <div class="testContainer">
    <div>
      子组件
    </div>
  </div>

</template>
<script setup>
import {defineExpose } from "vue";
const  name ="testB"
const logEvent = () => {
  console.log('我是子组件方法')
}
defineExpose({
  logEvent,
  name
})
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

六:v-model

TestPage.vue父组件

<template>
  <div>
    这是父组件
    <!-- <TestB v-model:name="name" v-model:num="num"> 
    </TestB> -->
     <TestB :name="name" @update:name="name = $event" />
    <p>
      姓名{{ name }}
      <br>
      数量{{ num }}
      </br>
    </p>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import TestB from '@/components/TestB.vue'

const name=ref('张三');
const num=ref(123);
</script>

testB.vue子组件

<template>
  <div class="testContainer">
    <div>
      子组件
      <button @click="myClick">点击</button>
    </div>
  </div>

</template>
<script setup>
import {defineEmits  } from "vue";
const emit = defineEmits(["name","num"])

const myClick = () => {
  emit("update:name", "改个新名字")
  emit("update:num", 666)
}
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

子组件通过 defineEmits获取到然后用emit("update:修改的属性", 修改的内容)进行修改父组件的内容,,注意:update:是固定写法
v-model扩展:defineModel():

defineModel()宏的简单说明:父子组件的数据双向绑定,不用emit和props的繁重代码
版本要求:必须要3.4+

示例场景:父组件引入一个子组件弹窗,点击就父传子(props)弹出子组件弹窗,子组件里面有个按钮点击就子传父(emit)关闭

代码示例
TestPage.vue 父组件

<template>
  <div>
    这是父组件
    <TestB v-if="showDevice" v-model="showDevice"> 
    </TestB>
    <p>
      {{ showDevice }}
      </br>
    </p>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import TestB from '@/components/TestB.vue'
const showDevice = ref(true) // 控制子组件的显示和隐藏
</script>

TestB.vue子组件

<template>
  <div class="testContainer">
    <div>
      子组件
      <button @click="handleClickCancel">点击取消子组件弹窗</button>
    </div>
  </div>

</template>
<script setup>
import {defineModel   } from "vue";
const model = defineModel();
console.log(model)

const handleClickCancel = () => {
  console.log(model);
  
  model.value = false;
}
</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

七:provide与indect注入传值

provide和inject叫依赖注入,是vue官方提供的API,它们可以实现多层组件传递数据,无论层级有多深,都可以通过这API实现。

TestPage.vue(这个可以是父组件也可以是子组件)

<template>
  <div>
    这是父组件
    <TestB > 
    </TestB>
    <p>
      {{ showDevice }}
      </br>
    </p>
  </div>
</template>

<script  setup>
import { ref,provide  } from 'vue'
import TestB from '@/components/TestB.vue'
provide('path', '/project/')

const showDevice = ref('xxxx') // 控制子组件的显示和隐藏
provide('name', showDevice)
</script>

TestB.vue(子组件或者孙组件)

<template>
  <div class="testContainer">
    <div>
      子组件
    </div>
  </div>

</template>
<script setup>
import {inject   } from "vue";
const path = inject('path')
console.log(path);
const  name = inject('name')
console.log(name.value);

</script>
<style scoped>
.testContainer {
  background-color: #f8f8f8;
}
</style>

八:路由传参

路由跳转分为query和params传参
query示例:

// 传递方
const query = { id: 9527, name: '天天鸭' }
router.push({ path: '/user', query })

// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.query)

param示例:

// 发送方
router.push({
   name: 'test', 
   params: {
       name: '天天鸭'
   }
})
 
// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.params) // { name: '天天鸭' }

state传参示例:

// 发送方
const state= { name: '天天鸭' }
router.push({ path: '/user', state })
 
// 接收方直接使用
console.log(history?.state?.name)

九:vuex传参

十:pinia传参

十一:浏览器缓存传参

十二:通过window对象全局挂载全局对象或者属性

// 定义
window.duname = '天天鸭'
window.duObj = { test: '看看对象' }
// 引用
console.log( window.duname);   // 天天鸭 
console.log( window.duObj);   // {test: '看看对象'}

十二:app.config.globalProperties

// main.js
import { createApp } from 'vue'

const app = createApp(App)

app.config.globalProperties.msg = 'hello'

// 其它页面引用
import { getCurrentInstance } from "vue";

const { proxy } = getCurrentInstance() // 使用proxy,类似于vue2的this

console.log(proxy.msg);    // hello
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容