1.props
vue2中组件间数据共享大概有这几种方式:
props 和 $emit、v-model、 .sync、 ref、$bus、$attrs、$listeners、$parent、$children、$root、provide、inject、vuex在vue3中数据共享的方式要分成几种情况,由于在组合式api中vue2语法也可以使用,但是官方不推荐这种混合的语法,所以我们只讨论在组合式api中进行组件间数据共享.大致分成两种情况,普通的setup写法和setup的语法糖形式写法
用 props 传数据给子组件
1.1普通的setup写法
one.vue组件:
<template>
  <div>
    <h3>父组件</h3>
    <!-- 第一步在子组件的UI标签上,绑定自义定属性,自定义属性的值就是要传递给子组件的值 -->
    <two :coffe="coffe" :title1="title1" :tea="tea"></two>
  </div>
</template>
<script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {
  components:{
    two
  },
  setup(props) {
    const coffe=ref("厚乳拿铁!");
    const title1=ref("我是父组件数据");
    const tea=toRaw(reactive(["乌龙茶","西湖龙井"])) ; 
    return {
      coffe,
      title1,
      tea
    }
  }
}
</script>two.vue组件:
<template>
  <div>
    <h3>子组件</h3>
    <p>接收父组件传递过来的值:{{coffe}}---{{tea}}---{{title1}}</p>
  </div>
</template>
<script>
export default {
  //第二步:在子组件中使用props接收父组件传值过来的
  //如果在子组件中不接收父组件传递过来的数据,setup(props)中的props参数是没有值的
  //props的写法有两种:对象和数组
  /** 
    props:{
       coffe:{
         type:String,//传递的数据类型
         required:true, //是否必须要传递
         default:'coffe' //默认值
       },
       tea:{
         type:Array,
         required:true,
         default:'tea'
       },
       title1:{
         type:String
       }
     },
     */
    //props数组的简写形式
    props:["coffe","tea","title1"],
    setup(props) {
      console.log(props);
    } 
}
</script>
1.2在setup语法糖写法
父组件Home.vue组件:
<template>
  <div class="home">
    <h3>home.vue组件</h3>
    <child :isshow="isshow" :money="money"></child>
  </div>
</template>
<script setup>
import {ref,reactive} from "vue";
  import child from "./child"
  const isshow=ref(false);
  const money=ref("我这有一些钱拿去花吧!")
</script>子组件child.vue组件
<template>
  <div>
    <h3>child.vue组件</h3>
    <p>接收父组件传递过来的数据(setup语法糖):----{{money}}</p>
    <p><button @click="toggle">控制盒子的显示和隐藏</button> </p>
    <div class="child-box" v-if="isshow"></div>
  </div>
</template>
<script setup>
//defineProps:在语法糖中不需要引入 直接使用
const props=defineProps({
  isshow:Boolean,
  money:{
    type:String,
    default:''
  }
})
console.log(props) //Proxy {isshow: false, money: '我这有一些钱拿去花吧!'}
const toggle=()=>{
  //想要使用传递过来的数据:props.属性   
    console.log(props.isshow); //false
    //点击按钮让child-box盒子显示
    //需要修改父组件传递过来的isshow属性,这时会报一个警告:reactivity.esm-bundler.js?89dc:521 Set operation on key "isshow" failed: target is readonly. 
    //props.isshow=true;
}
</script>
<style lang="scss" scoped>
.child-box{
  width: 200px;
  height: 200px;
  background: purple;
}
</style>1.3修改父组件传递过来的属性
<script setup>
//defineProps:在语法糖中不需要引入 直接使用
const props=defineProps({
  isshow:Boolean,
  money:{
    type:String,
    default:''
  }
})
const toggle=()=>{
  //想要使用传递过来的数据:props.属性   
    console.log(props.isshow); //false
    //点击按钮让child-box盒子显示
    //需要修改父组件传递过来的isshow属性,这时会报一个警告:reactivity.esm-bundler.js?89dc:521 Set operation on key "isshow" failed:         //target is readonly. 
    props.isshow=true;
}
</script>由于vue是单向数据流,父组件传递给子组件的属性,子组件只能使用不能修改,在vue2中可以使用.sync修饰符.但是在vue3中v-bind的.sync修饰符和组件的model选项被删除了.在vue3中我们可以直接使用v-model语法糖进项绑定,绑定属性发生了变化,属性名是 modelValue, 事件名是:update:modelValue.
在one.vue中:
<template lang="">
  <div>
    <h3>父组件</h3>
    <p>count的值为:{{count}}</p>
    <!-- 如果想要获取原生事件对象:
    加入绑定事件函数fn fn(e) {e就是事件对象}
    如果绑定的是js表达式,提供的是一个默认的变量$event 
    如果想要获取自定义事件
    绑定函数fn fn(data){ data触发自定义事件的参数}
    如果绑定的是js表达式 此时 $event代表触发自定义事件的传参 -->
    <two :modelValue="count"  @update:modelValue="count=$event" ></two>
  </div>
</template>
<script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {
  components:{
    two
  },
  setup(props) {
     const count=ref(100)
    return {
      count
    }
  }
}
</script>two.vue组件:
Vue3在setup函数上提供了两个参数,一个props,一个是context下面的emit方法,分别来处理输入和输出。
<template lang="">
  <div>
    <h3>子组件</h3>
    <p><button @click="changModelValue">点击修改count</button> </p>
  </div>
</template>
<script>
export default {
    props:["modelValue"],
    setup(props,{emit}) {
    const changModelValue=()=>{
        //改变父组件传递过来的数据
        emit("update:modelValue",200)
    }
      return {
        changModelValue
      }
    } 
}
</script>可以简写为v-model
<!-- :modelValue="count"   @update:modelValue="count=$event"可以简写为v-model="count" -->
   <two :coffe="coffe" :title1="title1" :tea="tea" v-model:count="count"  ></two>
const changModelValue=()=>{
        emit("update:count",200)
  }setup语法糖的写法:
//定义抛出事件的名字 
//defineEmits适用于 Vue3.2版本,不需要引入
const emit=defineEmits(["update:count"])
 const changModelValue=()=>{
        emit("update:count",200)
    }2.$emit
子组件向父组件传值可以使用$emit
vue3在setup函数上提供了两个参数,一个props,一个是context下面的emit`方法,分别来处理输入和输出。
2.1setup写法
子组件two.vue
<template>
  <div>
    <h3>子组件</h3>
    <p>子组件向父组件传值</p>
    <p><button @click="myclick">点击向父组件传递数据</button> </p>
  </div>
</template>
<script>
import {ref,reactive} from "vue"
export default {
    setup(props,{emit}) {
    const movie={
        name:'这个杀手不太冷静',
        price:56
      }
    const myclick=()=>{
        emit("send",movie)
    }
      return {
        myclick
      }
    } 
}
</script>父组件one.vue:
<template>
  <div>
   <two @send="resiveMovie"  ></two>
    <p>接收从子组件传递过来的值:{{resiveData.film}}</p>
  </div>
</template>
<script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {
  components:{
    two
  },
  setup(props) {
    const resiveData=reactive({})
     const resiveMovie=(film)=>{
       console.log(film)
       resiveData.film=film;
     }
    return {
      coffe,
      resiveMovie,
       resiveData
    }
  }
</script>2.2setup语法糖写法
child.vue子组件:
<template>
  <div>
   <p>
      <input type="text" v-model="str"  @input="changStr" />
    </p>
  </div>
</template>
<script setup>
import {ref} from "vue"
const emit=defineEmits(["sendStr"])
const str=ref("")
const changStr=()=>{
     emit("sendStr",str)
}
</script>home.vue父组件:
<template>
  <div>
   <p>接收子组件传递过来的数据:{{message}}</p>
    <child  @sendStr="reaiveStr"  ></child>
  </div>
</template>
<script setup>
import {ref} from "vue"
const message=ref("")
const reaiveStr=(msg)=>{
     message.value=msg
}
</script>3.ref
子组件child.vue
//向外部暴露属性或者方法适用于Vue3.2版本, 不需要引入
    defineExpose({
        childName: "这是子组件的属性",
        someMethod(){
            console.log("这是子组件的方法")
        }
    })父组件home.vue
<template>
     <child  :money="money"   v-model:isshow="isshow" @sendStr="reaiveStr"  ref="childCom"   ></child>
   <p><button @click="handlerClick">点击获取子组件</button> </p>
</template>
<script setup>
   const childCom=ref(null);
   const handlerClick = () => {
   console.log(childCom.value)
        console.log(childCom.value.childName) // 获取子组件对外暴露的属性
        childCom.value.someMethod() // 调用子组件对外暴露的方法
    }
</script>4.attrs
attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合
4.1setup中获取
父组件:
<template>
  <two :coffe="coffe" :title1="title1" :tea="tea" class="demo" ></two>
</template>子组件:
<script>
    props:["coffe"],
    setup(props,{emit,attrs}) {
      console.log("attrs",attrs) //{title1: '我是父组件数据', tea: Array(2), class: 'demo'}
    }
</script>4.2setup语法糖获取
父组件:
<template>
  <child  :money="money" ></child>
</template>子组件:
<script setup>
   import {ref,useAttrs} from "vue"
//接收attrs
 const attrs = useAttrs();
 console.log("attrs",attrs) //{money: '我这有一些钱拿去花吧!}
</script>5. provide / inject
provide / inject 为依赖注入
provide:可以让我们指定想要提供给后代组件的数据或
inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用
// Parent.vue
<script setup>
    import { provide } from "vue"
    provide("people",{name:"张三",age:18});
    provide("id","1005678");
</script>
// Child.vue
<script setup>
    import { inject } from "vue"
   const people=inject("people"); //{ "name": "张三", "age": 18 }
const id=inject("id"); //id:1005678
</script>









