【学习笔记】《玩转Vue3全家桶》----如何像搭建积木一样开发网页?

前言: 在我们的项目中,组件无处不在,通过对组件功能的封装,可以像搭积木一样开发网页。下面,就了解一下Vue的组件化机制吧。

一、什么是组件化开发

    vue允许我们自定义组件,把一个功能的模板(template)封装在一个.vue文件中。如下图,我们把每个组件的逻辑和样式,也就是把JavaScript和CSS封装在一起,方便在项目中复用整个组件的代码。
在这里插入图片描述
    vue已经把组件化的机制实现得很好了,只需要在这个基础之上,去掌握和学习组件化在使用上的设计理念。这样做的母的是实现高效的代码复用,在后续的项目开发中,我们会把组件分成两个类型,一个是通用型组件,一个是业务型组件。
    通用型组件就是各大组件库的组件风格,包括按钮、表单、弹框等通用功能。业务型组件包含业务的交互逻辑,包括购物车、登录注册等,会和我们不同的业务强绑定。
    组件的开发由于要考虑代码的复用性,会比通常的业务开发要求更高,需要有更好的可维护性和稳定性的要求。为了帮助理解设计组件的要点,选择一个简单的组件来展开。
    需求如下:有一个评级需求,就是在前端页面上,能够让商品显示1到5的评分。以此为例,来了解组件的设计思路。

二、渲染评级分数

    其实,对于评级需求,就可以使用组件。这样,只需要一行代码就可以实现评级需求。比如,rate是1到5的整数,通过slice方法,直接渲染出对应数量的星星即可。

"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate)

    查看这行代码效果,传入评分值rate即可。代码运行效果如下,其中星星代表着评价的等级,由rate的值来决定。
在这里插入图片描述
    每个组件渲染的内容并不完全一样,这是写组件时首先要确认的内容。每个组件在项目中的不同地方,会渲染不同的内容。
    在这里写的这个组件就是根据rate的值,来渲染出不同数量的星星。进入到src/components目录,新建Rate.vue,然后,写出下面的代码。下面,使用defineProps来规范传递数据的格式,这里规定了组件会接收外部传来的value
属性,并且只能是数组,然后,根据value的值计算出评分的星星。

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

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

    使用组件的方式就是使用:value的方式,通过属性把score传递给Rate组件,就能够在页面上根据score的值,显示出三颗实心的星星。下面展示了如何使用Rate组件来显示3颗星星。

<template>
<Rate :value="score"></Rate>
</template>

<script setup>
import {ref} from 'vue'
import Rate from './components/Rate1.vue'
let score = ref(3)
</script>

    根据传递的score值显示不同的内容,也可以更进一步,回到Rate.vue代码里,加入如下的代码,如在组件中内置一些主题颜色,加入CSS的内容。如下代码,Rate组件新接收一个属性theme,默认值是orange。在Rate组件中内置了几个主题颜色,根据传递的theme计算出颜色,并且使用:style渲染。

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

<script setup>
import { defineProps,computed, } from 'vue';
let props = defineProps({
    value: Number,
    theme:{type:String,default:'orange'}
})
console.log(props)
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value))

const themeObj = {
  'black': '#00',
  'white': '#fff',
  'red': '#f5222d',
  'orange': '#fa541c',
  'yellow': '#fadb14',
  'green': '#73d13d',
  'blue': '#40a9ff',
}
const fontstyle = computed(()=> {
    return `color:${themeObj[props.theme]};`
})

</script>

    在完成了上面代码所示的过程,也就是通过theme渲染星星颜色这一步,然后就可以使用下面的代码,传递value和theme这两个属性,并且可以很方便地复用组件。

<Rate :value="3" ></Rate>
<Rate :value="4" theme="red"></Rate>
<Rate :value="1" theme="green"></Rate>

    下图,可以看到上面三个组件渲染的结果:
在这里插入图片描述

三、组件事件

    评级需求完成了,但是,评级组件还需要具备修改评分的功能,所以,需要让组件的星星可点击,并且,让点击后的评分值能否传递到父组件。
    在vue中,我们使用emit来对外传递事件,这样元素就可以监听Rate组件内部的变化。现在我们对Rate组件进行改造,首先由于星星都是普通文本,没有办法单独绑定click事件。所以要对模板进行改造,每个星星都用span包裹,并且使用width属性控制宽度,支持小数的评分显示。
    回到Rate.vue组件,添加下面的代码,把★和☆用span包裹,并绑定鼠标的mouseover事件。然后,通过:style,可以设置实心五角星★的宽度,实现一样的评级效果。

<template>
<div :style="fontstyle">
    <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>
// ...其他代码
// 评分宽度
let width = ref(props.value)
function mouseOver(i){
    width.value = i 
}
function mouseOut(){
    width.value = props.value
}
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>

    因为现在是通过宽度显示星星,所以,还可以支持3.5分的小数评级,并且支持鼠标滑过的时候,选择不同的评分。如下,可以使用Rate组件。

<Rate :value="3.5"></Rate>

    效果如下所示:
在这里插入图片描述
    然后,在点击五角星选择评分的时候,把当前评分传递给父组件即可。在Vue3中,使用defineEmit来定义对外“发射”的数据,在点击评分的时候触发即可。下面的defineEmit代码就展示了点击评分后,向父元素“发射”评分数据num。


<template>
  省略代码
   <span @click="onRate(num)" @mouseover="mouseOver(num)" v-for='num in 5' :key="num"></span>

</template>
<script setup>
import { defineProps, defineEmits,computed, ref} from 'vue';

let emits = defineEmits('[update-rate]') // 定义emits
function onRate(num){
    emits('update-rate',num)
}
</script>

    在下面的代码中,我们使用@update-rate接收Rate组件emit的数据,并且修改score的值,这样就完成了数据修改后的更新。


<template>

<h1>你的评分是 {{score}}</h1>
<Rate :value="score" @update-rate="update"></Rate>

</template>

<script setup>
import {ref} from 'vue'
import Rate from './components/Rate1.vue'
let score = ref(3.5)
function update(num){
    score.value = num
}

</script>

    现在组件的示意图如下,通过defineProps定义了传递数据的格式,通过defineEmits定义了监听的函数,最终实现了组件和外部数据之间的同步。
在这里插入图片描述

四、组件的v-model

    上面的Rate组件中数据双向同步的需求,在表单领域很常见。在input 标签上使用 v-model 这个属性就实现了这个需求。在自定义组件上我们也可以用 v-model,对于自定义组件来说,v-model 是两个语法,也就是:传入属性和接收组件传递数据和的简写。
    在下面的代码中,首先我们把属性名修改成 modelValue,然后如果我们想在前端页面进行点击评级的操作,我们只需要通过 update:modelValue 这个 emit 事件发出通知即可。

let props = defineProps({
	modelValue: Number,
	theme:{type:String,default:'orange'}
})
let emits = defineEmits(['update:modelValue'])

    然后,按照如下代码中的方式,使用Rate这个组件,也就是直接使用v-model绑定score变量。这样,就可以实现value和onRate两个属性的效果。

<template>

<h1>你的评分是 {{score}}</h1>
<Rate v-model="score"></Rate>
</template>

五、插槽

    和HTML的标签使用类似,很多时候,也需要给组件中传递内容。就像下面的代码中click并不是button标签的属性,而是子元素,button标签会把子元素渲染在居中的位置。

<button> click </button>

    Rate组件也是类似的,在vue中直接使用slot组件来显示组件的子元素,也就是所谓的插槽。在下面的代码中,使用组件渲染Rate组件的子元素。

<template>
<div :style="fontstyle">
	<slot></slot>
	<div class="rate" @mouseout="mouseOut">
		<span @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
		<span class="hollow" :style="fontwidth">
			<span @click="onRate(num)" @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
		</span>
	</div>
</div>
</template>

    现在使用Rate组件的时候,组件的子元素都会放在评级组件之前。除了文本,也可以传递其他组件或者html标签。下面代码显示的结果,第一个Rate组件显示课程评分,第二个Rate组件前面显示一个图片。

<Rate v-model="score">课程评分</Rate>
<Rate v-model="score">
    <img width="14" src="/favicon.ico">
</Rate>

总结:

    首先,我们用 props 属性传递的方式,通过传递的 value 属性去决定显示的星星数量,这也是设计组件的时候首先就要考虑的。一个组件库首先要实现的,就是通过 props 属性渲染内容,而在 Rate 组件里,我们可以根据 value 属性去渲染显示了几颗星星。
    然后为了让用户可以点击评分,我们优化了显示的方式,每个★包裹一个 span 标签,并且绑定了 mouseover 和 mouseout 事件显示鼠标悬停的样式,最后在★标签的 click 事件上,对外通知事件,告知父组件数据的变化。
    对于这个通知机制,我们使用 defineEmits 定义的方式来实现,这也是 Vue 组件中重要的数据交换机制。emits 配合 props,这样我们在使用一个组件的时候,就实现了给组件传递数据,并且我们也能够监听组件内部数据的变化。最后我们通过规范 props 和 emit 的名字,实现了直接在自定义的组件之上使用 v-model。
参考博客:
《玩转Vue3全家桶》–大圣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值