文章目录
- style-scoped
- style-module
- 类和内联样式
- props
- 练习
style-scoped
- 可以直接通过style标签来编写样式,
- 如果直接通过style标签写样式,此时编写的样式是全局样式
- 会影响到所有的组件
- 可以为style标签添加一个scoped属性,
- 这样样式将成为局部样式,只对当前组件生效
如何实现的?-
当我们在组件中使用scoped样式时,
vue会自动为组件中的所有元素生成一个随机的属性
形如:data-v-7a7a37b1
生成后,所有的选择器都会在最后添加一个 [data-v-7a7a37b1]
h1 -> h1[data-v-7a7a37b1]
.box1 -> .box1[data-v-7a7a37b1] -
注意:
- 随机生成的属性,除了会添加到当前组件内的所有元素上,
也会添加到当前组件引入的其他组件的根元素上,这样设计
是为了,可以通过父组件来为子组件设置一些样式。如果要
使引入的其他组件生效,引入的组件要为单根组件。
- 随机生成的属性,除了会添加到当前组件内的所有元素上,
-
<script setup>
import MyBox from "./components/MyBox.vue"
</script>
<template>
<div class="app">
<h1>今天天气真不错!</h1>
<div class="box1">App中的box1</div>
<MyBox></MyBox>
</div>
</template>
<!--
可以直接通过style标签来编写样式,
如果直接通过style标签写样式,此时编写的样式是全局样式
会影响到所有的组件
-->
<!-- <style>
h1 {
background-color: #bfa;
}
.box1 {
width: 200px;
height: 200px;
background-color: yellowgreen;
}
</style> -->
<!-- 可以为style标签添加一个scoped属性,
这样样式将成为局部样式,只对当前组件生效
如何实现的?
- 当我们在组件中使用scoped样式时,
vue会自动为组件中的所有元素生成一个随机的属性
形如:data-v-7a7a37b1
生成后,所有的选择器都会在最后添加一个 [data-v-7a7a37b1]
h1 -> h1[data-v-7a7a37b1]
.box1 -> .box1[data-v-7a7a37b1]
- 注意:
- 随机生成的属性,除了会添加到当前组件内的所有元素上,
也会添加到当前组件引入的其他组件的根元素上,这样设计
是为了,可以通过父组件来为子组件设置一些样式。如果要
使引入的其他组件生效,引入的组件要为单根组件。
-->
<style scoped>
h1 {
background-color: orange;
}
.box1 {
width: 200px;
height: 200px;
background-color: #bfa;
}
/*
将组件中所有的 h2的字体颜色设置为黄色
.app h2 --> .app h2[xxxxx] 此时子组件的h2不生效,因为 样式添加到了单根组件的div上了
.app h2[data-v-7a7a37b1] 没用deep
.app[data-v-7a7a37b1] h2 用了deep
*/
.app :deep(h2) {
color: yellow;
}
/*
:global() 全局选择器
*/
:global(div) {
border: 1px red solid;
}
</style>
<!-- <style>
div {
border: 1px red solid;
}
</style> -->
style-module
- 自动的对模块中的类名进行hash化来确保类名的唯一性
- 在模板中可以通过(默认) $style.类名 使用
- 也可以通过module的属性值来指定变量名
<script setup>
import MyBox from "./components/MyBox.vue"
</script>
<template>
<div class="app">
<h1>今天天气真不错!</h1>
<div :class="classes.box1">App中的box1</div>
<MyBox></MyBox>
</div>
</template>
<!--
css 模块
- 自动的对模块中的类名进行hash化来确保类名的唯一性
- 在模板中可以通过(默认) $style.类名 使用
- 也可以通过module的属性值来指定变量名
-->
<style module="classes">
.box1 {
background-color: #bfa;
}
</style>
类和内联样式
<script setup>
const arr = ["box1", "box2", "box3"]
const arr2 = [{ box1: true }, { box2: false }, { box3: true }]
const style = {
color: "red",
backgroundColor: "#bfa"
}
</script>
<template>
<h1 class="header">我爱Vue</h1>
<div :class="arr" :style="style">我是div</div> <!--相当于<div class="box1 box2 box3>" -->
<div :class="arr2" :style="style">我是div</div>
</template>
<style scoped>
.header {
background-color: orange;
}
</style>
props
- 子组件中的数据通常不会在子组件中直接定义,这样会导致数据和视图发生耦合!
- 子组件中的数据通常会在创建组件实例时确定!
- 父组件可以通过 props 来将数据传递给子组件
- 使用props
- 先在子组件中定义props
- 父组件可以通过props来向子组件传递数据
- 注意:父组件传递给子组件的props都是只读的,无法在子组件修改
即使可以修改,我们也尽量不要在子组件中去修改父组件的数据
如果非得要改,具体方法后边再讲(自定义事件) - 属性名
- 定义属性名时,属性名要遵循驼峰命名法
- 注意:父组件传递给子组件的props都是只读的,无法在子组件修改
App.vue
<script setup>
import MyBox from "./components/MyBox.vue"
import { ref } from "vue"
const count = ref(0)
const obj = ref({
count: 0
})
</script>
<template>
<h1>我是App根组件</h1>
<MyBox :count="123" :obj="obj" maxLength="1231"></MyBox>
<button @click="obj.count++">点我一下</button>
</template>
Mybox.vue
<script setup>
/*
父组件可以通过props来向子组件传递数据
注意:父组件传递给子组件的props都是只读的,无法在子组件修改
即使可以修改,我们也尽量不要在子组件中去修改父组件的数据
如果非得要改,具体方法后边再讲(自定义事件)
属性名
- 定义属性名时,属性名要遵循驼峰命名法
*/
// 定义props
// count = 0
// obj = {count = 0}
const props = defineProps(["count", "obj", "maxLength"])
const props = defineProps({
count: Number,//类型限制,实际作用不大
obj: Object,
isCheck: Boolean,
maxLength: {
type: String,//maxLength的类型
required: true,//maxLength是否必传
default: "哈哈",
validator (value) {//检查传过来的参数是否合法,返回false不合法
return value !== "嘻嘻"
}
}
})
console.log(props)
</script>
<template>
<div>
<h1>{{ props.maxLength }}</h1>
<h2>我是子组件 MyBox {{ props.obj.count }}</h2>
<button @click="props.count++">MB的按钮</button> <!--无法修改-->
<button @click="props.obj.count++">MB的按钮</button> <!--可以修改,obj不可修改,但属性可以修改。不建议这样操作-->
<hr />
</div>
</template>
<style scoped>
div {
color: tomato;
}
</style>
练习
App.vue
<script setup>
import { reactive, ref } from 'vue'
import TabItem from './components/TabItem.vue'
import TabList from './components/TabList.vue'
import Tab from './components/Tab.vue'
const players = reactive([
{
name: '梅西',
img: '/images/messi.png',
rate: 1,
hot: 437890
},
{
name: 'C罗',
img: '/images/ronaldo.png',
rate: 2,
hot: 397890
},
{
name: '内马尔',
img: '/images/neymar.png',
rate: 3,
hot: 367890
}
])
const teams = reactive([
{
name: '巴西',
img: '/images/巴西.jpg',
rate: 1,
hot: 437890
},
{
name: '法国',
img: '/images/法国.jpg',
rate: 2,
hot: 357890
},
{
name: '荷兰',
img: '/images/荷兰.jpg',
rate: 3,
hot: 267890
}
])
// 获取最大热度,也就是排名第一人的热度
const playMaxHot = players[0].hot
const teamMaxHot = teams[0].hot
</script>
<template>
<Tab>
<template #0>
<TabList :items="players" :maxHot="playMaxHot"></TabList>
</template>
<template #1>
<TabList :items="teams" :maxHot="teamMaxHot"></TabList>
</template>
</Tab>
</template>
Tab.vue
<script setup>
import { ref } from 'vue'
//创建一个变量来记录选项卡的状态
const current = ref(0) //0 表示球员 1表示球队
</script>
<template>
<!-- 选项卡的外部容器 -->
<div class="tab-wrapper">
<!-- 选项卡的头部 -->
<header class="tab-head">
<!-- 定义两个按钮 -->
<div @click="current = 0" class="tab-button" :class="{active : current === 0}">热门球员</div>
<div @click="current = 1" class="tab-button" :class="{ active: current === 1 }">热门球队</div>
</header>
<!-- 选项卡的主体 -->
<div class="main">
<div v-show="current === 0">
<!-- 球员 -->
<slot name="0"></slot>
</div>
<div v-show="current === 1">
<!-- 球队 -->
<slot name="1"></slot>
</div>
</div>
</div>
</template>
<style scoped>
.tab-wrapper {
box-sizing: border-box;
width: 800px;
padding: 20px;
background-color: rgb(45, 83, 211);
margin: 0 auto;
}
.tab-head {
display: flex;
border-radius: 10px;
overflow: hidden;
}
.tab-button {
background-color: #fff;
font-style: 30px;
padding: 10px 0;
text-align: center;
flex: auto;
transition: 0.5s;
}
.tab-button:not(.active):hover {
color: rgb(187, 3, 52)
}
.active {
background-color: rgb(187, 3, 52);
color: #fff;
}
</style>
TabList.vue
<script setup>
import TabItem from './TabItem.vue'
//定义参数
const props = defineProps(["items", "maxHot"])
</script>
<template>
<div class="tab-list">
<TabItem v-for="player in props.items" :item="player" :maxHot="props.maxHot"></TabItem>
</div>
</template>
<style scoped>
.tab-list {
margin: 30px
}
</style>
TabItem.vue
<script setup>
import Photo from './Photo.vue'
import HotBar from './HotBar.vue'
//创建一个响应式对象
const props = defineProps(['item'])
const item = props.item
</script>
<template>
<div class="tab-item">
<!-- 图片 -->
<Photo :src="item.img" :alt="item.name" :rate="item.rate"></Photo>
<!-- 描述 -->
<div class="desc">
<span class="name">{{ item.name }}</span>
<HotBar :hot="item.hot" :maxHot="555555"></HotBar>
</div>
</div>
</template>
<style scoped>
.tab-item {
display: flex;
margin-bottom: 40px;
}
.desc {
display: flex;
flex-flow: column;
justify-content: space-evenly;
font-size: 30px;
color: #fff;
flex: auto;
margin-left: 30px;
}
</style>
HotBar.vue
<script setup>
import { computed } from 'vue';
const props = defineProps(['hot', 'maxHot'])
const width = computed(() => {
//计算百分比
return props.hot / props.maxHot * 100 + '%'
})
</script>
<template>
<div class="hot-bar">
<div class="inner">{{ props.hot }}热度</div>
</div>
</template>
<style scoped>
.hot-bar {
background-color: rgb(3, 37, 103);
border-radius: 20px;
text-indent: 0.5em;
}
.inner {
width: v-bind(width);
border-radius: 20px;
background-image: linear-gradient(90deg,
rgba(187, 3, 52) 50%,
rgba(66, 2, 12));
white-space: nowrap;
/*文字不换行 */
}
</style>
Photo.vue
<script setup>
import { computed } from 'vue'
const props = defineProps(["src", "alt", "rate"])
const color = computed(() => {
//判断颜色
if (props.rate == 1) {
return "rgb(254,45,70)"
} else if (props.rate == 2) {
return "rgb(245,102,1)"
} else {
return "rgb(247, 169, 1)"
}
})
</script>
<template>
<!-- 图片 -->
<div class="photo">
<img :src="props.src" alt="props.alt">
<span>{{ props.rate }}</span>
</div>
</template>
<style scoped>
.photo {
position: relative;
width: 150px;
background-color: #fff;
border-radius: 20px;
overflow: hidden;
}
.photo img {
width: 100%;
vertical-align: middle;
}
.photo span {
position: absolute;
left: 0;
top: 0;
width: 50px;
height: 50px;
background-color: v-bind(color);
font-size: 20px;
font-weight: bold;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-bottom-right-radius: 20px;
}
</style>