vue动画
cnpm install animate.css --save yarn add animate.css // 安装
import 'animate.css' // 在哪用在哪引入
3 .0 ------------------------------------------------------------------------------------------
<transition-group appear name="animate__animated animate__bounce" enter-active-class="animate__zoomInDown" leave-active-class="animate__zoomOutDown">
<!-- //这里包住要动画内容 要一个跟元素或删除标签的-group -->
<!-- 动画结束 -->
</transition-group>
部分效果图
App.vue
<template>
<!-- <div id="nav"> -->
<!--
vue3中移除了tag属性 新增了custom属性 custom可以用来自定义router-link的内容
但是使用了之后会导致路由无法跳转 这时候需要v-slot="{navigate}" 通过事件触发navigate方法就能跳转页面
假如有两个路由地址 第一个 /home 第二个是 /home/index
exact-acitve-class 精确匹配后才会添加的class类名
active-class 包含有就会添加的class类名
vue2中的写法
<router-view to="/" tag="button" exact-active-class="active">home</router-view>
-->
<!-- <router-link to="/" custom v-slot="{navigate, isExactActive}">
<button @click="navigate" :class="isExactActive ? 'active' : ''">home</button>
</router-link> |
<router-link to="/about" custom v-slot="{navigate, isExactActive}">
<button @click="navigate" :class="isExactActive ? 'active' : ''">about</button>
</router-link> | -->
<!-- </div> -->
<!-- 动画 -->
<div>
<div>
<router-view v-slot="{ Component }">
<transition name="ani">
<component :is="Component" class="page1"></component>
</transition>
</router-view>
</div>
<!-- <router-view></router-view> -->
</div>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
// text-align: center;
width: 100%;
height: 100%;
position: relative;
}
// 动画触发时组件共存,是块级元素,组件分上下动画僵硬,定位让组件在一行显示,
.page1 {
width: 100%;
position: absolute;
top: 0px;
left: 0;
}
// 进入时
.ani-enter-from {
left: 100%;
}
//进入过程
.ani-enter-active {
transition: all 0.5s linear;
}
//离开过程
.ani-leave-active {
transition: all 0.5s linear;
transform-origin: center;
}
//离开时
.ani-leave-to {
left: -100%;
}
</style>
home.vue
<template>
<div class="home">
<div class="tabs">
<span
v-for="(item, i) in tabs"
:key="item.id"
:class="num == i ? 'active' : ''"
@click="tabclick(i)"
>{
{ item.name }}</span
>
</div>
<!-- lits -->
<div
class="list"
v-for="item in $store.state.data"
:key="item.id"
v-show="num == item.status"
>
<div class="one">
<img :src="item.img" alt />
</div>
<div class="two">
<p>{
{ item.name }}</p>
<p class="price">¥{
{ item.price }}</p>
<section class="footer">
<p>{
{ item.payNum }}人付款</p>
<p @click="add(item)">+</p>
</section>
</div>
</div>
</div>
</template>
<script>
import { useStore } from "vuex";
import { ref, reactive } from "vue";
import { useRouter } from "vue-router";
export default {
components: {},
setup() {
const store = useStore();
const router = useRouter();
const num = ref(0);
const tabs = reactive([
{
name: "推荐",
id: 0,
},
{
name: "母婴",
id: 1,
},
{
name: "鞋包",
id: 2,
},
{
name: "食品",
id: 3,
},
{
name: "数码",
id: 4,
},
]);
function tabclick(i) {
num.value = i;
}
function add(item) {
store.commit("add", item);
router.push("/About");
}
store.dispatch("getData");
return {
store,
tabclick,
num,
tabs,
add,
router,
};
},
};
</script>
<style lang="scss" scoped>
.tabs {
display: flex;
align-items: center;
width: 100%;
height: 50px;
background-color: #4b0082;
span {
flex-basis: 20%;
height: 100%;
line-height: 50px;
color: #fff;
text-align: center;
}
}
.list {
display: flex;
width: 100%;
height: 130px;
background-color: #fff;
margin-bottom: 20px;
.one {
flex-basis: 30%;
height: 100%;
img {
width: 100%;
height: 100%;
}
}
.two {
flex-basis: 70%;
height: 100%;
p {
&:nth-child(1) {
margin-top: 20px;
}
}
.price {
color: #4b0082;
margin: 15px 0 15px 15px;
}
.footer {
padding: 0 15px;
margin-top: 10px;
display: flex;
width: 100%;
justify-content: space-between;
p {
&:nth-child(2) {
width: 40px;
height: 25px;
text-align: center;
line-height: 25px;
border-radius: 25px;
background-color: #4b0082;
font-size: 20px;
color: #fff;
}
}
}
}
.active {
color: #ec1f10 !important;
}
}
</style>
About.vue
<template>
<div>
<button @click="$router.go(-1)">返回</button>
<transition-group
appear
name="animate__animated animate__bounce"
enter-active-class="animate__zoomInDown"
leave-active-class="animate__zoomOutDown"
>
<!-- //这里包住要动画内容 要一个跟元素或删除标签的-group -->
<!-- list -->
<div class="list" v-for="item in $store.state.cardDate" :key="item.id">
<div class="one">
<input
type="checkbox"
:checked="item.checked"
@change="ck(item.id)"
/>
<img :src="item.img" alt />
</div>
<div class="two">
<p v-html="item.name"></p>
<p v-html="item.price"></p>
</div>
<div class="three">
<span @click="item.num > 1 ? item.num-- : 1">-</span>
<span>{
{ item.num }}</span>
<span @click="item.num++">+</span>
</div>
</div>
<!-- 动画结束 -->
</transition-group>
</div>
<button @click="del">删除所选</button>
<button>已选{
{ $store.getters.num }}</button>
<button>总数{
{ $store.getters.priceAll }}</button>
<input
type="checkbox"
v-model="$store.state.vmckall"
@click="ckAll($event || e)"
/>全选
</template>
<script>
import { useStore } from "vuex";
import { onBeforeMount } from "vue";
import "animate.css";
export default {
components: {},
setup() {
onBeforeMount(() => {
// ...
// 在小括号里不用赋值,不在小括号箭头函数要生命一个变量接受
store.commit("mount");
});
const store = useStore();
function del() {
store.commit("del");
}
function ck(id) {
store.commit("ck", id);
}
function ckAll(e) {
store.commit("ckAll", e.target.checked);
}
return {
del,
store,
ck,
ckAll,
};
},
};
</script>
<style lang="scss" scoped>
.list {
display: flex;
justify-content: space-between;
padding: 0 15px;
align-items: center;
width: 100%;
height: 130px;
background-color: #fff;
.one {
display: flex;
img {
width: 60%;
height: 100%;
margin-left: 10px;
}
}
.two {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
}
.three {
display: flex;
flex-direction: column;
span {
display: inline-block;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
background-color: #ccc;
&:nth-child(2) {
margin: 10px 0;
}
}
}
}
</style>
源码在主页资源
结语:
希望大家都能早早下班,没有bug,陪陪家人朋友