购物车 ajax 接口请求拆分到 service 文件夹中
// goods.js
import axios from 'axios'
export default {
getGoodsInfo () {
return axios.get('/api/goods')
.then(res => {
// 处理数据格式,并返回
const {code, data: goodsInfo, slider, keys} = res.data;
if (code) {
return {goodsInfo, slider, keys};
} else {
return null;
}
});
}
}
路由切换动态
// 1. 使用 transition 组件 嵌套 router-view 组件
<transition name="route-move">
<router-view class="child-view" />
</transition>
// 2. 通过 CSS 定义路由切换动画
.route-move-enter {
// 入场前状态
transform: translate3d(-100%, 0, 0);
}
.route-move-leave-to{
// 离场后状态
transform: translate3d(100%, 0, 0);
}
.route-move-enter-active,
.route-move-leave-active{
// 激活状态
transition: transform 0.3s;
}
购物车动画,使用 Vue 的 JS 方式的半场动画
// CartAnim.vue
<template>
<div class="ball-wrap">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="ball" v-show="show">
<div class="inner">
<div class="cubeic-add"></div>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "cartAnim",
data () {
return {
show: false
}
},
methods: {
start(el) {
// 启动动画接口,传递点击按钮元素
this.el = el;
// 适应.ball显示,激活动画钩子
this.show = true;
},
beforeEnter(el) {
// 把小球移动到点击的DOM元素所在位置
const rect = this.el.getBoundingClientRect();
// 转换为用于绝对定位的坐标
const x = rect.left - window.innerWidth /2;
const y = -(window.innerHeight - rect.top - 10 - 20);
// ball 只移动 y 轴
el.style.transfrom = `translate3d(0, ${y}px, 0)`;
// inner 只移动 x 轴
const inner = el.querySelector(".inner");
inner.style.transform = `translate3d(${x}px, 0, 0)`;
},
enter(el, done) {
// 获取offsetHeight就会重绘
document.body.offsetHeight;
//指定动画结束位置
el.style.transform = `translate3d(0, 0, 0)`;
const inner = el.querySelector(".inner");
inner.style.transform = `translate3d(0, 0, 0)`;
el.addEventListener("transitionend", done);
},
afterEnter(el) {
// 动画结束, 开始清理工作
this.show = false;
el.style.display = "none";
this.$emit("transitionend");
}
}
}
</script>
<style scoped>
.ball-wrap .ball{
position: fixed;
left: 50%;
bottom: 10px;
z-index: 100000;
color: red;
transition: all .5s cubic-bezier(0.49, -0.29, 0.75, 0.41);
}
.ball-wrap .ball .inner{
16px;
height: 16px;
transition: all 0.5s linear;
background: #f00;
border-radius: 50%;
}
.ball-wrap .ball .inner .cubeic-add {
font-size: 22px;
}
</style>
// CartAnim 組件的使用
// 1. 引入组件
import CartAnim from '@/components/CartAnim.vue';
// 2. 挂载到组件选项中
components: {
CartAnim
}
// 3. 在组件模板中 使用组件,并在商品列表组件上监听启动事件
<cart-anim ref="ca"></cart-anim>
<good-list @cartanim="$refs.ca.start($event)" />
// 4. 在 good-list 组件中通过 $emit 派发自定义事件
this.$emit('cartanim', event.target);
全局创建组件实例函数
import Vue from 'vue';
export default function(Component, props) {
// 创建vue实例
const instance = new Vue({
render: h => h(Component, { props });
}).$mount();
// 把生成的dom追加至body中
document.body.appendChild(instance.$el);
// 添加一个销毁方法
const comp = instance.$children[0];
comp.remove = function () {
document.body.removeChild(instance.$el);
instance.$destroy();
}
return comp;
}
// 在入口 main.js 中注入方法
import create from './utils/create'
Vue.prototype.$create = create;
// 在组件中使用 $create 方法
const anim = this.$create(CartAnim);
anim.start(el);
anim.$on("transitionend", anim.remove);