一、显示头部
1.1 新建头部组件 在components目录下新建Header.vue文件。其中该组件接收两个参数:title和showback。title代表头部组件的标题内容;showback代表是否显示后退按钮。
{{title}}
>
>
export default {
props: {
title: {
type: String,
default: '',
},
showback: {
type: Boolean,
default: true,
},
},
methods: {
back() {
this.$router.back();
}
},
}
lang="stylus" scoped>
.header {
position: relative;
height: 44px;
line-height: 44px;
text-align: center;
background: #edf0f4;
.cubeic-back {
position: absolute;
top: 0;
left: 0;
padding: 0 15px;
color: #fc915b;
}.extend {
position: absolute;
top: 0;
right: 0;
padding: 0 15px;
color: #fc915b;
}
}
1.2 全局引入组件 修改main.js文件:
import KHeader from './components/Header.vue'// 全局引入Header.vue
Vue.component('k-header', KHeader)
1.3 使用组件 在首页Home.vue中显示组件。
运行效果:
文章图片
二、管理访问历史 2.1 Vue插件开发 资料地址:https://cn.vuejs.org/v2/guide/plugins.html
现在我们想定义一个访问浏览历史记录的实例方法。我们把该方法添加到Vue.prototype上实现。
第一步:新建utils目录,该目录存放我们项目中定义的工具;
第二步:新建history.js文件,在该文件中实现插件功能;
import Vue from 'vue'const History = {
_history: [], // 历史记录
install(vue) {
// 给Vue对象添加实例方法
Object.defineProperty(Vue.prototype, '$routerHistory', {
get() {
return History;
}
});
},
push(path) { // 存储访问页面
this._history.push(path);
},
pop() { // 删除历史页面
this._history.pop();
},
canBack() {
return this._history.length > 1;
}
}export default History;
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。
第三步:通过全局方法Vue.use()安装插件;
import History from '../utils/history'Vue.use(History)
插件安装成功后,可以使用History访问插件方法。
History.pop();
// 删除访问历史的最后记录
2.2 路由配置 第一步:扩展Router功能,新增后退方法。
import VueRouter from 'vue-router'VueRouter.prototype.goBack = function() {
this.isBack = true;
// 新增isBack属性,true代表当前操作是后退
this.back();
// 调用路由的back方法执行后退
}
第二步:定义路由拦截方法。
import History from '../utils/history'// 把History当成插件引入
Vue.use(History) // 记录访问历史
router.afterEach((to, from) => {
if (router.isBack) {
// 如果执行后退,删除访问历史的最后记录
History.pop();
router.isBack = false;
} else {
// 如果不是执行后退,则添加访问历史记录
History.push(to.path);
}
});
2.3 改造后退按钮 (1)修改Header.vue的back方法:
methods: {
back() {
// this.$router.back();
this.$router.goBack();
// 替换成该方法
}
},
(2)修改后退条件:
运行效果:
文章图片
二、页面切换特效 修改App.vue,把transition标签的name属性改为动态属性。
在data返回的json对象中添加transitionName属性。
data () {
return {
...
transitionName: 'route-forward',
}
},
当路由发生变化时,同步更新transitionName属性。
watch: {
// 监控route状态变化。当路由发生变化,同步tabs选中状态
$route(route) {
this.selectedLabel = route.path;
this.transitionName = this.$router.transitionName;
}
},
修改页签样式:
/* 页签滚动条样式 */
.cube-tab-bar-slider {
top: 0;
}/* 动画设置 */
.route-forward-enter { /* 入场前 */
transform: translate3d(-100%, 0, 0);
}.route-forward-leave-to { /* 出场后 */
transform: translate3d(100%, 0, 0);
}.route-back-enter { /* 入场前 */
transform: translate3d(100%, 0, 0);
}.route-back-leave-to { /* 出场后 */
transform: translate3d(-100%, 0, 0);
}.route-forward-enter,
.route-forward-leave-active,
.route-back-enter,
.route-back-leave-active { /* 播放动画过程中 */
transition: transform 0.3s;
/* 完成动画需要的时间 */
}
修改路由配置文件,在router中定义transitionName属性。如果router.isBack为true,代表是回退操作,则transitionName为route-back;如果router.isBack为false,代表前进操作,则设置transitionName为route-forward。
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';
// 前进特效
}
});
三、加购物车添加动画效果 实现效果:
文章图片
3.1 定义小球 在Home.vue模版中定义一个div元素,该元素代表动画中的小球。
其中v-show属性用于控制小球的显示。因此,需要定义ball.show属性。
data() {
return {
...
ball: {
show: false,
el: null, // 目标dom的引用
}
}
},
ball对象有两个属性:show代表小球的显示状态,true代表显示,false不显示;el代表的是小球所属DOM元素的引用。
小球样式:
/* 圆球样式 */
.ball-wrap {
.ball {
position: fixed;
left: 50%;
bottom: 10px;
z-index: 100000;
color: red;
transition: all 0.5s cubic-bezier(0.49, -0.29, 0.75, 0.41);
.inner {
width: 16px;
height: 16px;
transition: all 0.5s linear;
.cubeic-add {
font-size: 22px;
}
}
}
}
3.2 添加动画事件 transition标签有三个事件属性,它们分别代表动画执行的三种不同状态。
@before-enter:动画开始前
@enter:动画进行中
@after-enter:动画结束后
下面是三个事件对应的处理方法:
methods: {
...
beforeEnter(el) {
console.log('动画开始前...');
// 设置小球初始位置
// 小球移动到点击的位置
// 1. 获取点击的dom位置
const dom = this.ball.el;
const rect = dom.getBoundingClientRect();
console.log(rect.top, rect.left);
// 2. 把小球移动到点击的位置
const x = rect.left - window.innerWidth / 2;
const y = -(window.innerHeight - rect.top - 10 - 20);
el.style.display = "block";
// ball只移动y
el.style.transform = `translate3d(0, ${y}px, 0)`;
const inner = el.querySelector(".inner");
// inner只移动x
inner.style.transform = `translate3d(${x}px,0,0)`;
},
enter(el, done) { // el代表当前动画的元素
console.log('动画执行中...');
// 把小球移动到初始位置 加上动画
// 获取offsetHeight就会重绘,前面的变量名随意 主要为了eslint校验
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) {
console.log('执行动画结束后的清理工作...');
// 隐藏小球
this.ball.show = false;
el.style.display = 'none';
},
},
3.3 为加购物车按钮派发事件 首先修改GoodsList.vue,在addCart方法中派发addCart事件。
// 向父组件Home派发点击事件
this.$emit('addCart', $event.target);
// $event.target代表事件发生的元素
然后首页商品列表中监听addCart事件。
定义addCart事件的处理方法。
onAddCart(el) {
console.log('显示小球');
this.ball.el = el;
// 初始化ball.el属性
this.ball.show = true;
// 显示小球
},
四、全局组件 下面以toast为例,介绍如何定义全局组件。
// toast组件的定义格式
const toast = this.$createToast({
time: 2000,
txt: message || '登录失败',
type: 'error'
});
toast.show();
4.1 定义组件 首先,在components目录下新建Notice.vue。
{{item.content}}
>
export default {
name: 'notice',
}
【前端|Vue电商项目实战(三)】定义alerts属性,该属性用于存储多个通知。
data() {
return {
alerts: [],
}
},
在created方法中初始化通知id。通知id应该是自增长。
created() {
this.id = 0;
},
定义添加和删除通知的方法。
methods: {
// 添加通知,options参数代表通知选项(duration-显示时间,content-通知内容)
add(options) {
// 通知id自增
const id = 'id_' + this.id++;
// 创建通知对象
const _alert = {
...options,
id,
}
// 保存通知
this.alerts.push(_alert);
// 自动关闭
const duration = options.duration || 1;
// 延迟关闭时间,单位为秒
setTimeout(() => {
this.del(id);
}, duration * 1000);
},
// 删除通知
del(id) {
for (let i = 0;
i < this.alerts.length;
i++) {
const alert = this.alerts[i];
if (alert.id === id) {
this.alerts.splice(i, 1);
break;
}
}
}
},
添加样式:
.alert {
position fixed
width 100%
top 30
left 0
text-align center
.alert-content {
display inline-block
padding 8px
background #fff
margin-bottom 10px
}
}
4.2 使用create-api模块创建通知组件 资料地址:https://didi.github.io/cube-ui/#/zh-CN/docs/introduction
4.2.1 导入create-api模块
修改main.js文件:
import {createAPI} from 'cube-ui'
4.2.2 加载Notice组件
修改main.js文件:
import Notice from './components/Notice.vue'createAPI(Vue, Notice, true);
createAPI方法第三个参数代表是否单例。true代表Notice组件是单例,即在应用中只创建一次。
4.2.3 使用Notice组件
修改GoodsList.vue,在addCart方法中显示通知。
addCart($event, item) {
// 把添加购物车的商品放在state中
this.$store.commit('addCart', item);
// 显示通知
const notice = this.$createNotice();
notice.add({duration: 2, content: '加购物车成功'});
},
4.3 自定义通知组件 第一步:新建一个services目录,然后在该目录下新建notice.js文件。
第二步:导入Notice.vue,并且定义一个创建Notice实例的静态方法。
import Vue from 'vue';
import Notice from '@/components/Notice.vue'// 给Notice添加一个属性函数,用于创建Notice组件实例,并动态编译后的Notice组件挂载到页面上
Notice.getInstance = props => {
// 创建一个Vue实例
const instance = new Vue({
// 渲染函数,该函数用于把指定模版渲染为DOM
render(h) {
return h(Notice, {props});
}
}).$mount();
// 把Notice组件添加到Body元素中
document.body.appendChild(instance.$el);
// instance.$el用于获取当前实例里面的DOM
// 从vue实例中获取notice实例
return instance.$children[0];
}
注意:Notice实例在应用中只需要创建一次即可。所以我们通过对单例来创建Notice实例。
// 单例创建Notice实例
let noticeInstance = null;
function getInstance() {
if (noticeInstance == null) {
noticeInstance = Notice.getInstance();
}
return noticeInstance;
}
第三步:对外暴露接口。
// 暴露接口
export default {
info({duration = 2, content = ''}) {
getInstance().add({
duration,
content
});
}
}
第四步:把notice配置到Vue实例中。
import notice from '@/services/notice'Vue.prototype.$notice = notice;
第五步:测试。
// 添加购物车
addCart($event, item) {
// 把添加购物车的商品放在state中
this.$store.commit('addCart', item);
// 显示通知
// const notice = this.$createNotice();
// notice.add({duration: 2, content: '加购物车成功'});
this.$notice.info({duration: 3, content: '加购物车成功'});
},
运行效果:
文章图片
推荐阅读
- #|vue电商实战(基础理论)day0
- 中间件|【实战篇】egg+vue+mongodb实践开发在线文档管理平台——水墨文档
- Node.js|【Node.js】Express
- 【前端可视化】|echarts使用结合时间轴timeline动态刷新案例
- 笔记|TypeScript简记(一)
- DGIOT支持工业设备租赁以及远程管控
- 2022秋招前端面试题(六)(附答案)
- 2022年最新开课吧-孤尽训练营002期—T31购票+抢票系统
- opencv|C++ OpenCV霍夫变换--圆检测