App.vue
{{item.label}}
{{cartTotal}}
data() {
return {
transitionName: 'route-forward',
selectLabel: "/",
tabs: [
{
label: "Home",
value: "/",
icon: "cubeic-home"
},
{
label: "Cart",
value: "/cart",
icon: "cubeic-mall"
},
{
label: "Me",
value: "/about",
icon: "cubeic-person"
}
]
};
},
created() {
// 初始化⻚签设置,避免⻚⾯刷新
this.selectLabel = this.$route.path;
},
watch: {
$route(route) {
// 监听路由变化并动态设置⻚签选中状态
this.selectLabel = route.path;
this.transitionName = this.$router.transitionName
}
},
methods: {
changeHandler(val) this.$router.push(val);
}
},
轮播图和商品列表
goods服务,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;
}
});
}
};
轮播图、商品列表,Home.vue
购物⻋状态,cart.js
export default {
state: { // 购物⻋初始状态
list: JSON.parse(localStorage.getItem("cart")) || []
},
mutations: {
addcart(state, item) { // 添加商品⾄购物⻋
const good = state.list.find(v => v.title == item.title);
if (good) {
good.cartCount += 1;
} else {
state.list.push({
...item,
cartCount: 1
});
}
},
cartremove(state, index) { // count-1
if (state.list[index].cartCount > 1) {
state.list[index].cartCount -= 1;
}
},
cartadd(state, index) { // count+1
state.list[index].cartCount += 1;
}
},
getters: {
cartTotal: state => { // 商品总数
let num = 0;
state.list.forEach(v => {
num += v.cartCount;
});
return num;
},
total: state => { // 总价
return state.list.reduce(
(total, item) => total + item.cartCount * item.price,
0
);
}
}
}
动画设计
添加购物⻋动画,CartAnim.vue
使⽤动画,Home.vue
import CartAnim from "@/components/CartAnim.vue";
components: { CartAnim }
触发动画,GoodList.vue
addCart(e,item) { // 需要传递事件⽬标
this.$store.commit("addcart", item);
// 触发动画事件
this.$emit('cartanim',e.target)
}
动态全局组件设计与设计
**使⽤cube-ui的create-ap
注册,main.js**
import {createAPI} from 'cube-ui'
import CartAnim from '@/components/CartAnim'
createAPI(Vue, CartAnim, ['transitionend']) //
调⽤api,Home.vue
methods: {
startCartAnim(el) {
const anim = this.$createCartAnim({
onTransitionend() {
anim.remove();
}
});
anim.start(el);
}
}
组件动态创建并挂载的具体实现./utils/create.js
import Vue from "vue";
// 创建函数接收要创建组件定义
function create(Component, props) {
// 创建⼀个Vue新实例
const instance = new Vue({
render(h) {
// render函数将传⼊组件配置对象转换为虚拟dom
console.log(h(Component, { props }));
return h(Component, { props });
}
}).$mount(); //执⾏挂载函数,但未指定挂载⽬标,表示只执⾏初始化、编译等⼯作
// 将⽣成dom元素追加⾄body instance.$el vue实例的真实dom
document.body.appendChild(instance.$el);
// 给组件实例添加销毁⽅ instance.$children[0] 所有组件的实例的数组
const comp = instance.$children[0];
comp.remove = () => {
//从body移除dom 全局組件頻繁創建與刪除
document.body.removeChild(instance.$el);
instance.$destroy();
};
return comp;
}
// 暴露调⽤接⼝
export default create;
挂载到vue实例上,main.js
import create from '@/utils/create'
Vue.prototype.$create = create;
调⽤,Home.vue
startCartAnim(el) {
const anim = this.$create(CartAnim);
anim.start(el);
anim.$on("transitionend", anim.remove);
}
⻚头组件
组件定义,Header.vue
使⽤,Home.vue
import KHeader from '@/components/Header.vue';
components: {
GoodList,KHeader,
}
**返回按钮状态⾃动判断:history.length是不可靠的,它既包含了vue app路由记录,也包括其他
⻚⾯的。可以添加⼀个⾃定义的历史记录管理栈,创建./utils/history.js**
const History = {
_history: [], // 历史记录堆栈
install(Vue) {
// vue插件要求的安装⽅法
Object.defineProperty(Vue.prototype, "$routerHistory", {
get() {
return History;
}
});
},
push(path) {
// ⼊栈
this._current += 1;
this._history.push(path);
},
pop() {
// 出栈
this._current -= 1;
return this._history.pop();
},
canBack() {
return this._history.length > 1;
}
};
export default History;
router.js中引⼊,添加⼀个后退⽅法并监听afterEach从⽽管理记录
import History from "./utils/history";
Vue.use(History);
Router.prototype.goBack = function() {
this.isBack = true;
this.back();
};
router.afterEach((to, from) => {
if (router.isBack) {
History.pop();
router.isBack = false;
router.transitionName = "route-back";
} else {
History.push(to.path);
router.transitionName = "route-forward";
}
});
使⽤,Header.vue
methods: {
back() {this.$router.goBack();}
}
后退动画,App.vue
data() {
return {
transitionName: 'route-forward'
};
},
watch: {
$route() {
// 动态设置动画⽅ this.transitionName = this.$router.transitionName
}
},
/* ⻚⾯滑动动画 */
/* ⼊场前 */
.route-forward-enter {
transform: translate3d(-100%, 0, 0);
}
.route-back-enter {
transform: translate3d(100%, 0, 0);
}
/* 出场后 */
.route-forward-leave-to {
transform: translate3d(100%, 0, 0);
}
.route-back-leave-to {
transform: translate3d(-100%, 0, 0);
}
.route-forward-enter-active,
.route-forward-leave-active,
.route-back-enter-active,
.route-back-leave-active {
transition: transform 0.3s;
}