学习内容:Vue3 setup语法糖
1、实例:轮播图效果
2、实现过程(轮播图(子组件)+左右按钮(父页面))
准备页面(App.vue:父页面+Carousel.vue:子组件)
3、Carousel.vue:子组件
使用setup语法糖写法
vue3的编译宏:
不使用语法糖写法
Carousel.vue代码,提供setup语法糖写法
<template>
<div v-show="imgs.length" class="carousel">
<div class="imgs" :style="{transform: `translateX(-${index}00%)`}">
<!-- :style="{transform: `translateX(-${index}00%)`,}:
:style:样式绑定,当表达式的值改变时,元素的样式也会相应地更新
translateX(-${index}00%):X轴(水平方向)上移动元素
-${index}00%:模版字符串,元素会向左移动其自身宽度的 index00% ,例如index:1,向左移动自身100%
表示水平移动的位置 -->
<!-- 存放图片 -->
<img v-for="(item, i) in imgs" :key="i" :src="item" alt="" />
</div>
<!-- 四个半透明白色点 -->
<!-- :class="{ active: i === index }":表示高亮哪一个点 -->
<div class="indicators">
<span v-for="(item, i) in imgs" :key="i" :class="{ active: i === index }" @click="switchTo(i)"></span>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
// defineProps、defineEmits:编译器宏
const props = defineProps({
imgs: {
type: Array,
default: () => [],
},
})
const emit = defineEmits(['change'])
defineExpose({
switchTo
})
const index = ref(0);
function switchTo(i) {
if (i < 0) {
i = 0
} else if (i > props.imgs.length - 1) {
i = props.imgs.length - 1
}
if (i === index.value) {
return;
}
index.value = i
emit('change', i);
}
</script>
<style scoped>
.carousel {
width: 300px;
height: 300px;
overflow: hidden;
position: relative;
}
.imgs {
width: 100%;
height: 100%;
display: flex;
transition: 0.3s;
}
.imgs img {
width: 100%;
height: 100%;
}
.indicators {
position: absolute;
left: 50%;
bottom: 20px;
transform: translateX(-50%);
display: flex;
column-gap: 7px;
}
.indicators span {
width: 10px;
height: 10px;
background: #aaa;
border-radius: 50%;
cursor: pointer;
}
.indicators span.active {
background: #fff;
}
</style>
App.vue父页面代码:
使用语法糖
不使用语法糖:
父页面代码:
<!-- <template>
<div id="app">
<CheckEditor v-model="checked" v-model:title.trim="title" />
<p>選中狀態{{ checked }}</p>
<p>商品名稱{{ title }}</p>
</div>
<div class="container">
<div>
<strong>编辑</strong>
<div class="list">
<CheckEditor v-for="item in products" :key="item.id" v-model="item.sell" v-model:title="item.title">
</CheckEditor>
</div>
</div>
<div class="list">
<strong>销售中:</strong>
<div>
<template v-for="(item, index) in sells" :key="item.id">
<span>{{ index + 1 }}</span>
<strong>{{ item.title }}</strong>
</template>
</div>
</div>
</div>
<div>
<div v-if="isAccount">
<label>账号:</label>
<input type="text" />
</div>
<div v-else>
<label>手机登录:</label>
<input type="text" />
</div>
<button @click="isAccount = !isAccount">切换登录方式</button>
</div>
</template>
<script>
import CheckEditor from './components/CheckEditor.vue';
import { ref, computed } from "vue";
const defaultSells = [
{
id: 1, sell: true, title: "iphone1"
},
{
id: 2, sell: false, title: "iphone2"
},
{
id: 3, sell: true, title: "iphone3"
},
{
id: 4, sell: true, title: "iphone4"
}
]
export default {
components: {
CheckEditor,
},
setup() {
const productsRef = ref(defaultSells);
const sellsRef = computed(() => productsRef.value.filter((it) => it.sell))
const isAccount =ref(false)
return {
products: productsRef,
sells: sellsRef,
isAccount: isAccount
}
},
};
</script>
<style scoped>
.container {
margin-top: 50px;
width: 880px;
margin: 50px auto;
}
.list {
display: flex;
margin: 1em 0;
align-items: center;
}
strong {
margin-right: 1em;
}
</style> -->
<!-- <template>
<div id="nav">
<router-link to="/">Home</router-link>
|
<span v-if="loading">loading....</span>
<template v-else-if="user">
<span>用户名</span>
<a class="ml-5" href="" @click.prevent="handleLoginOut">退出</a>
</template>
<router-link v-else to="/login">Login</router-link>
</div>
<router-view />
</template>
<script>
import {useStore} from "vuex";
import {computed} from "vue";
import { useRoute } from "vue-router";
export default {
setup(){
const store = useStore();
const router = useRoute()
const handleLoginOut = async ()=>{
await store.dispatch("loginUser/loginOut")
router.push("/login")
}
return {
loading:computed(()=>store.state.loginUser.loading),
user:computed(()=>store.state.loginUser.user),
handleLoginOut
}
}
}
</script>
<style scoped>
body {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style> -->
<template>
<div class="container">
<!-- 引入组件 change 是改变父组件的页面dom-->
<Carousel ref="compRef" :imgs="datas" @change="handleChange"></Carousel>
<div class="current">
<!-- :disabled="currentIndex === 0":当前图片为第一张时,左按钮禁用 -->
<button class="btn" @click="change(currentIndex - 1)" :disabled="currentIndex === 0">
左
</button>
{{ currentIndex }}
<!-- :disabled="currentIndex === datas.length - 1":当前图片为最后一张时,右按钮禁用 -->
<button class="btn" @click="change(currentIndex + 1)" :disabled="currentIndex === datas.length - 1">
右
</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import Carousel from './components/Carousel.vue';
const currentIndex = ref(0);
const datas = [//图片数据
new URL(`./assets/bule.png`, import.meta.url),
new URL(`./assets/airplane.png`, import.meta.url),
new URL(`./assets/red.png`, import.meta.url),
new URL(`./assets/sky.png`, import.meta.url),
];
const compRef = ref(null);
function handleChange(newIndex) {//改变 {{ currentIndex }}的值
currentIndex.value = newIndex
}
function change(i) {//点击按钮改变数据后,使用ref触发子组件方法
if (compRef.value) {
compRef.value.switchTo(i)
}
}
</script>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid slateblue;
}
.current {
display: flex;
column-gap: 10px;
margin-top: 30px;
align-items: center;
}
.btn {
border: none;
outline: none;
background: #409eff;
color: #fff;
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
text-align: center;
transition: 0.1s;
font-weight: 500;
user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.btn:hover {
background: #66b1ff;
}
.btn:active {
background: #3a8ee6;
}
.btn:disabled {
background: #66b1ff80;
cursor: not-allowed;
}
</style>
使用语法糖的switchTo方法
本次分享vue3使用语法糖的使用以及不使用语法糖使用的写法区别
1、写法上不在使用export default{}以及不需要注册组件
2、使用语法糖暴露的方法很干净,避免数据污染
3、简化了开发