美文网首页
vue3.x全家桶+vite(三)组件通信

vue3.x全家桶+vite(三)组件通信

作者: 感觉不错哦 | 来源:发表于2022-01-04 17:36 被阅读0次

组件

什么是组件,就是标签,除了浏览器自带的组件外,Vue 还允许我们自定义组件,把一个功能的模板(template)封装在一个.vue 文件中,组件的开发由于要考虑代码的复用性,会比通常的业务开发要求更高,需要有更好的可维护性和稳定性的要求。其实之前的demo就是组件,只是缺少了一点复用与交互

简单的组件

所有demo建立在有vue基础上,没有基础建议先学习vue2

<template>
    <div>
        home
        <Count :msg="msg"></Count>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Count from '../components/Count.vue'
    const msg = ref('我是传递的信息内容')
</script>

父组件传递的格式较为固定,使用V-bind 绑定变量名传递响应变量即可

<template>
    {{msg}}
</template>

<script>
export default {
    props:['msg']
}

</script>

<style scoped>

</style>

传统的Options Api是像这样接收父组件的传值,不考虑PropsType的情况

之前介绍过setup中的存在两个参数,分别是props,context,那么此处的props你没想错,就是用来可以接收父组件的传值的,但是需要props声明

<template>
    {{msg}}
</template>

<script>
export default {
    //如果不声明  接收到undefined
    props:['msg'],
    setup(props){
        console.log(props) //返回Proxy对象 Proxy:{msg:'。。。。值'}
    }
}

</script>

<style scoped>

</style>

在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 <script setup> 中是直接可用的

<template>{{ msg }}</template>

<script setup>
    const props = defineProps({ msg: String });
</script>

<style scoped>
</style>

那么第一个参数props主要就是这样,第二个参数context简单使用一些场景,context是一个对象,里面主要有三个属性 attrs,slots,emit,因此setup函数也可以写成 setup(props,{attrs,slots,emit})

attrs主要是子组件上显示的标签属性值,html标签都是可以自定义属性的嘛,emit很熟悉哈,它是通信函数的一个非常熟悉的一个关键字

<template>
    <div>
        home
        <Count :msg="msg" name="shengchao" age="99"></Count>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Count from '../components/Count.vue'
    const msg = ref('我是传递的信息内容')
</script>

现在 我在父组件中自定义了俩个熟悉,使用attrs可以在子组件中接收

<template>
    {{msg}}
</template>

<script>
export default {
    props:['msg'],
    setup(props,{attrs,slots,emit}){
        console.log(props) //返回Proxy对象 Proxy:{msg:'值'}
        console.log(attrs) // 返回Proxy对象 Proxy:{name:'shengchao',age:''99}
    }
}

</script>

<style scoped>

</style>

当然也可以使用context去接收,那么props大家知道可以直接使用插值,也就是{{}}在标签中使用,那么attrs 也是可以的

<template>
    {{msg}}
    <div>名字:{{$attrs.name}}</div>
    <div>年龄:{{$attrs.age}}</div>
</template>

<script>
export default {
    props:['msg'],
    setup(props,context){
        console.log(props) //返回Proxy对象 Proxy:{msg:'值'}
    }
}

</script>

<style scoped>

</style>

在语法糖中,由于没有setup函数,需要引入useAttrs,useAttrs()返回attrs对象,也可以用来赋值

<template>
    {{ msg }}
    <div>名字:{{ $attrs.name }}</div>
    <div>年龄:{{ $attrs.age }}</div>
</template>

<script setup>
    import { useAttrs } from 'vue'
    const props = defineProps({ msg: String });
    useAttrs()
</script>

<style scoped>
</style>

emit
父组件

<template>
    <div>
        home
        <Count :msg="msg" @getson="getson"></Count>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Count from '../components/Count.vue'
    const msg = ref('我是传递的信息内容')
    const getson = function(v){
        console.log(v)
    }
    
</script>

子组件

<template>
    {{ msg }}
    <button @click="backfather">click me</button>
</template>

<script>
export default {
    props: ['msg'],
    setup(props, context) {
        function backfather() {
            context.emit('getson', '子组件传递给父组件')
        }
        return { backfather }
    }
}
</script>

<style scoped>
</style>

button点击会触发backfather函数,接着emit函数,第一个参数是父组件自定义的触发名,第二个参数是子组件传递给父组件的值,那么这时候控制台会保警告,vue3新增了emits对象,用来更灵活的管理emit事件,用法与props类似,可以是简单的声明,也可以做一些拦截处理操作

// 与props相同,接收父组件的自定义事件名
emits:['getson']

这样警告就消失了

子组件

<template>
    {{ msg }}
    <button @click="backfather">click me</button>
    <button @click="backfatherAgain">click me</button>
</template>

<script>
import {ref} from 'vue'
export default {
    props: ['msg'],
    emits:{
        getson:null, //不做任何处理
        getson2: val=>{
            //val 传递的值
        if(val){
            //一些操作
        }else{
            console.error('报错了')
        }
        }
    },
    setup(props, context) {
        var flag = ref(false)
        function backfather() {
            context.emit('getson', '子组件传递给父组件')
        }
        function backfatherAgain(){
            context.emit('getson2', flag.value)
        }
        return { backfather,backfatherAgain,flag}
    }
}
</script>

<style scoped>
</style>

父组件

<template>
    <div>
        home
        <Count :msg="msg" @getson="getson" @getson2="getson2"></Count>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Count from '../components/Count.vue'
    const msg = ref('我是传递的信息内容')
    const getson = function(v){
        console.log(v) //子组件传递给父组件
    }
    const getson2 = function(v){
        console.log(v) //false
    }
    
</script>

需要注意的是,验证只是做一些操作,不会改变传递的值 所以父组件接收到的还是false

在语法糖中需要使用defineEmits去声明

<template>
    {{ msg }}
    <button @click="backfather">click me</button>
    <button @click="backfatherAgain">click me</button>
</template>

<script setup>
    const emit = defineEmits(["getson","getson2"])
    const props = defineProps({ msg: String });
    const backfather = function(){
        emit('getson','子组件传递给父组件')
    }
    const backfatherAgain = function(){
        emit('getson2', false)
    }
</script>

<style scoped>
</style>

实现一个评分星级组件

父组件

<template>
    <div>
        <Rate :score="score"></Rate>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Rate from '../components/Rate.vue'
    const score = ref(3)    
</script>

新建一个子组件,如果你用的是vscode,建议自己自定义代码片段,
点击左上角文件=>首选项=>用户片段

选择全局,这个就随便了,可以复制我的

"Print to console": {
    "prefix": "vsetup",
    "body": [
        "<template>",
        "$1",
        "</template>",
        "$2",
        "<script setup>",
        "$3",
        "</script>",
        "$4",
        "<style scoped>",
        "$5",
        "</style>"
    ],
    "description": "Log output to console"
}

输入vsetup就可以自动打出以上代码了,了解详情可以自行百度学习一下,
子组件

<template>
{{rate}}
</template>

<script setup>
import { computed } from 'vue'
const props = defineProps({ score: Number });
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5 - props.score, 10 - props.score))

</script>

<style scoped>
</style>

我们加点颜色上去,但是一个个加是不是太憨了,我们可以在父组件中,使用属性去加自己喜欢的颜色,当然也可以使用传值,这个无所谓,灵活使用一下我们学习的东西

<template>
    <div>
        <Rate :score="score"></Rate>
        <Rate :score="1" color="red"></Rate>
        <Rate :score="5" color="green"></Rate>
        <Rate :score="4" color="orange"></Rate>
    </div>
</template>
<script setup>
    import { ref } from "vue";
    import Rate from '../components/Rate.vue'
    const score = ref(3)    
</script>

子组件

<template>

<div :style="fontstyle">
    {{ rate }}
</div>

</template>

<script setup>
    import { computed,useAttrs } from 'vue'
    const props = defineProps({ score: Number });
    let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5 - props.score, 10 - props.score))
    //自定义一些颜色
    const colorObj = { 
        'black': '#000', 
        'white': '#fff', 
        'red': '#f5222d', 
        'orange': '#fa541c', 
        'yellow': '#fadb14', 
        'green': '#73d13d', 
        'blue': '#40a9ff', 
    }
    let attrs = useAttrs()
    let fontstyle = computed(()=>{
        return `color:${colorObj[attrs.color]}`
    })

</script>

<style scoped>
</style>

是不是有那味了!!

再创建一个组件,做一个交互组件

<template>
    <div>
        <div class="rate" @mouseout="mouseOut">
        <span @mouseover="mouseOver(num)" v-for="num in 5" :key="num">☆</span>
        <span class="hollow" :style="fontwidth">
            <span @mouseover="mouseOver(num)" v-for="num in 5" :key="num">★</span>
        </span>
    </div>
    </div>
</template>
<script setup>
    import { ref,computed } from 'vue'
    const props = defineProps({ score: Number });
    let width = ref(props.score)

    function mouseOver(i) {
        width.value = i
    }
    function mouseOut(num) {
        width.value = num
    }
    const fontwidth = computed(() => `width:${width.value}em;`)

</script>

<style scoped>
.rate {
    position: relative;
    display: inline-block;
}
.rate > span.hollow {
    position: absolute;
    display: inline-block;
    top: 0;
    left: 0;
    width: 0;
    overflow: hidden;
}
</style>

这是一个简易的鼠标hover评分效果,当然没那么完美,凑合看,复制代码看到效果后发现移开鼠标值没有变,因为改变的值没有返回给父组件

import { ref,computed } from 'vue'
const props = defineProps({ score: Number });
const emits = defineEmits(['getscore'])
let width = ref(props.score)

function mouseOver(i) {
    width.value = i
}
function mouseOut(num) {
    emit('getscore',num)
}
const fontwidth = computed(() => `width:${width.value}em;`)

引入emits 返回一下就好了,当然父组件需要设置接收事件

相关文章

网友评论

      本文标题:vue3.x全家桶+vite(三)组件通信

      本文链接:https://www.haomeiwen.com/subject/zwrqcrtx.html