vue 仿二手交易app_Vue项目开发-仿蘑菇街电商APP

最近快毕业了呜呜呜,准备找工作,但是缺乏项目经验,于是就在B站找相关的课程,学完之后便根据老师稳定的教导,以及自己稳定的心态,做了一个类似于蘑菇街的电商APP。(后端数据接口由老师提供,老师叫coderwhy,前端讲得真的很不错)。

蘑菇街作为中国最大女性购物社区,其APP的设计水平也毋庸置疑的

(1)准备工作

在阅读大神的博客时有人问里面使用的美工素材怎么得到的,其实很简单,下载一个APP,把APK格式修改成rar后解压,你会在目录下看到所有的素材。

(2)开始工作 项目目录:

由于是自己的练手之作,所以,莫得启动页面

下面是首页:

详情页

分类页

个人页面:

一. FeatureView独立组件封装FeatureViewdiv>a>img

二. TabControl独立组件的封装props -> titles

div>根据titles v-for遍历 div -> span{{title}}

css相关

选中哪一个tab, 哪一个tab的文字颜色变色, 下面border-bottomcurrentIndex

:key="(item,index)" class="tab-control-item"

:class="{active: index===currentIndex}"

@click="itemClick(index)">

{{item}}

export default {

name: 'TabControl',

props:{

titles:{

type:Array,

default(){

return [];

}

}

},

data() {

return {

currentIndex:0,

}

},

methods:{

itemClick(index){

this.currentIndex = index;

this.$emit('tabClick', index);

}

}

}

.tab-control{

display: flex;

text-align: center;

font-size: 15px;

height: 40px;

line-height: 40px;

background-color: #fff;

}

.tab-control-item{

flex: 1;

}

.tab-control-item span{

padding: 5px;

}

.active{

color: #ff5777;

}

.active span{

border-bottom: 3px solid var(--color-tint);

}

三. 首页商品数据的请求

3.1. 设计数据结构, 用于保存数据

goods: {

pop: page/list

new: page/list

sell: page/list

}

3.2. 发送数据请求在home.js中封装getHomeGoods(type, page)

在Home.vue中, 又在methods中getHomeGoods(type)

调用getHomeGoods('pop')/getHomeGoods('new')/getHomeGoods('sell')page: 动态的获取对应的page

获取到数据: resthis.goods[type].list.push(...res.data.list)

this.goods[type].page += 1

goods: {

pop: page1:/list[30]

new: page1/list[30]

sell: page1/list[30]

}

四. 对商品数据进行展示

4.1. 封装GoodsList.vue组件props: goods -> list[30]

v-for goods -> GoodsListItem[30]

GoodListItem(组件) -> GoodsItem(数据)

4.2. 封装GoodsListItem.vue组件props: goodsItem

goodsItem 取出数据, 并且使用正确的div/span/img基本标签进行展示

五. 对滚动进行重构: Better-Scroll

5.1. 在index.html中使用Better-Scrollconst bscroll = new BScroll(el, { })

注意: wrapper -> content -> 很多内容

1.监听滚动probeType: 0/1/2(手指滚动)/3(只要是滚动)

bscroll .on('scroll', (position) => {})

2.上拉加载pullUpLoad: true

bscroll .on('pullingUp', () => {})

3.click: falsebutton可以监听点击

div不可以

5.2. 在Vue项目中使用Better-Scroll在Profile.vue中简单的演示

对Better-Scroll进行封装: Scroll.vue

Home.vue和Scroll.vue之间进行通信Home.vue将probeType设置为3

Scroll.vue需要通过$emit, 实时将事件发送到Home.vue

六. 回到顶部BackTop

6.1. 对BackTop.vue组件的封装

6.2. 如何监听组件的点击直接监听back-top的点击, 但是可以直接监听?不可以, 必须添加修饰.native

回到顶部scroll对象, scroll.scrollTo(x, y, time)

this.$refs.scroll.scrollTo(0, 0, 500)

6.3. BackTop组件的显示和隐藏isShowBackTop: false

监听滚动, 拿到滚动的位置:-position.y > 1000 -> isShowBackTop: true

isShowBackTop = -position.y > 1000

七. 解决首页中可滚动区域的问题Better-Scroll在决定有多少区域可以滚动时, 是根据scrollerHeight属性决定scrollerHeight属性是根据放Better-Scroll的content中的子组件的高度

但是我们的首页中, 刚开始在计算scrollerHeight属性时, 是没有将图片计算在内的

所以, 计算出来的告诉是错误的(1300+)

后来图片加载进来之后有了新的高度, 但是scrollerHeight属性并没有进行更新.

所以滚动出现了问题

如何解决这个问题了?监听每一张图片是否加载完成, 只要有一张图片加载完成了, 执行一次refresh()

如何监听图片加载完成了?原生的js监听图片: img.onload = function() {}

Vue中监听: @load='方法'

调用scroll的refresh()

如何将GoodsListItem.vue中的事件传入到Home.vue中因为涉及到非父子组件的通信, 所以这里我们选择了事件总线bus ->总线

Vue.prototype.$bus = new Vue()

this.bus.emit('事件名称', 参数)

this.bus.on('事件名称', 回调函数(参数))

问题一: refresh找不到的问题第一: 在Scroll.vue中, 调用this.scroll的方法之前, 判断this.scroll对象是否有值

第二: 在mounted生命周期函数中使用 this.$refs.scroll而不是created中

问题二: 对于refresh非常频繁的问题, 进行防抖操作防抖debounce/节流throttle(课下研究一下)

防抖函数起作用的过程:如果我们直接执行refresh, 那么refresh函数会被执行30次.

可以将refresh函数传入到debounce函数中, 生成一个新的函数.

之后在调用非常频繁的时候, 就使用新生成的函数.

而新生成的函数, 并不会非常频繁的调用, 如果下一次执行来的非常快, 那么会将上一次取消掉

debounce(func, delay) {

let timer = null

return function (...args) {

if (timer) clearTimeout(timer)

timer = setTimeout(() => {

func.apply(this, args)

}, delay)

}

},

八. 上拉加载更多的功能

loadMore(){

this.getHomeGoods(this.currentType);

this.$refs.scroll.refresh();

}

九. tabControl的吸顶效果

9.1. 获取到tabControl的offsetTop必须知道滚动到多少时, 开始有吸顶效果, 这个时候就需要获取tabControl的offsetTop

但是, 如果直接在mounted中获取tabControl的offsetTop, 那么值是不正确.

如何获取正确的值了?监听HomeSwiper中img的加载完成.

加载完成后, 发出事件, 在Home.vue中, 获取正确的值.

补充:为了不让HomeSwiper多次发出事件,

可以使用isLoad的变量进行状态的记录.

注意: 这里不进行多次调用和debounce的区别

9.2. 监听滚动, 动态的改变tabControl的样式问题:动态的改变tabControl的样式时, 会出现两个问题:问题一: 下面的商品内容, 会突然上移

问题二: tabControl虽然设置了fixed, 但是也随着Better-Scroll一起滚出去了.

其他方案来解决停留问题.在最上面, 多复制了一份PlaceHolderTabControl组件对象, 利用它来实现停留效果.

当用户滚动到一定位置时, PlaceHolderTabControl显示出来.

当用户滚动没有达到一定位置时, PlaceHolderTabControl隐藏起来.

十. 让Home保持原来的状态

10.1. 让Home不要随意销毁掉keep-alive

10.2. 让Home中的内容保持原来的位置离开时, 保存一个位置信息saveY.

进来时, 将位置设置为原来保存的位置saveY信息即可.注意: 最好回来时, 进行一次refresh()

非父子组件通信:

我们在用Vue进行前端开发的时候,往往会遇到有很多个组件内,他们都有类似的data,类似的方法。这些大量重复的代码,如果正常编写出来,代码既不美观也不优雅,而且看起来也相当复杂。所以vue官方提供了一个极其好用的方式来解决这个问题

那就是mixin

先来看看官方的介绍混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

在Java开发中 如果我们遇到两个类有大量相似代码的时候,我们通常会定义一个父类,来讲这些重复代码写在一起,然后再让这两个类来继承父类的代码和方法。

class Animal{

run(){}

}

class Person extends Animal{

//run(){}

}

class Dog extends Animal{

//run(){}

}

而在Vue中,每个组件export出来的是对象,所以不能像类那样继承,于是Vue提供了类似于类的继承的方法 mixin

使用方法,在这里贴上自己项目的部分代码。

定义一个mixin.js 文件

import {debounce} from './utils';

export const itemListenerMixin = {

data(){

return {

itemImgListener: null,

}

},

methods:{

},

mounted(){

let newRefresh = debounce(this.$refs.scroll.refresh, 100)

this.itemImgListener = () => {

newRefresh()

}

this.$bus.$on('itemImgLoad', this.itemImgListener)

console.log("我是混入的东西")

}

}

mixin 里就跟一个正常的Vue的组件没有任何的区别,可以定义data,methods,生命周期函数等等。跟Java里面的父类和子类完全一样。只是调用的方法不一样而已。

两个调用mixin.js的组件

Detail.vue

import {itemListenerMixin} from "common/mixin";

mixins: [itemListenerMixin],

//其余代码均省略

Home.vue

import {itemListenerMixin} from "common/mixin";

mixins: [itemListenerMixin],

//其余代码均省略

只需要这样一小段代码,就可以调用到mixin.js 内定义的组件了。

而且在两个组件内,作用完全一样

当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。组件拥有最终发言权。当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

const myMixin = {

mounted() {

console.log('mixin!')

}

}

new Vue({

el: '#app',

mixins: [myMixin],

mounted() {

console.log('Vue instance!')

}

});

//Output in console

> mixin!

> Vue instance!

//mixin

const myMixin = {

methods: {

sayHello: function() {

console.log('mixin!')

}

},

mounted() {

this.sayHello()

}

}

//vue instance or component

new Vue({

el: '#app',

mixins: [myMixin],

methods: {

sayHello: function() {

console.log('Vue instance!')

}

},

mounted() {

this.sayHello()

}

})

// Output in console

> Vue instance!

> Vue instance!

我们可以看到,当他们之间没有发生同名冲突的时候,两个都正常打印了。而当他们发生冲突之后。你可以看到这里打印了两个Vue instance。这是因为第一个函数被调用之后,并没有被销毁,而是被重写了。然后被调用了两次

当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。

选项合并数据对象(data)在内部会进行递归合并,在和组件的数据发生冲突时以组件数据优先。

同名钩子函数(created,mounted...)将混合为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

值为对象的选项(methods, components 和 directives)将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对。

需要注意的是谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。大多数情况下,只应当应用于自定义选项。也可以将其用作 Plugins 以避免产生重复应用

所以Vue对mixin 设定了 自定义选项合并策略自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以向 Vue.config.optionMergeStrategies 添加一个函数:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {

// 返回合并后的值

}

对于多数值为对象的选项,可以使用与 methods 相同的合并策略:

var strategies = Vue.config.optionMergeStrategies

strategies.myOption = strategies.methods

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/533496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDL的综合和c语言的编译区别,C语言与verilog 的区别及相互转化

1,面对C语言比verilogHDL更加成熟,而且更加可靠,因为verilog的编译,查错工具大都是商业软件,因此没有像C语言一样得到广泛的应用,各种缺陷也较C来说 较多。基于这样的原因,在设计算法的硬件电路块时&#x…

linux几秒钟同步一次,Linux时间同步配置方法

由于是在做mongoDB的实验中再一次的遇到了mongos路由节点同步时由于ntp时间的问题导致同步非常的慢。故写了个时间同步的语句>while :; do rdate -s 192.168.109.129; sleep 2s; done > /dev/null 2>&1 &rdate: couldnt connect to host 192.168.109.129: Con…

c语言 socket 报文解析,C语言实现Socket简单通信

环境是linux,不过应该没什么影响,因为只用到了socket的基本用法,没有涉及pthread等。分为服务器端和客户端,服务器端监听端口发来的请求,收到后向客户端发送一个Hello World,客户机负责发送消息并打印收到的Hello Worl…

字典排序什么意思_字典排序问题

2018-01-03望京排序,立即想到用Python的内置函数sorted()Python 2.x 中sorted(...)sorted(iterable, cmpNone, keyNone, reverseFalse) --> new sorted listPython 3.x 中sorted(iterable, keyNone, reverseFalse)Return a new list containing all items from t…

bind() c语言,c/c++ 标准库 bind 函数详解

bind函数定义在头文件 functional 中。可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。bind函数:接收一个函数名作为参数,生成一个新的函数。auto newCallab…

单片机c语言编程要点,第1章单片机的C语言编程_2015要点.ppt

第1章单片机的C语言编程_2015要点1-* 第 1 章 结束!谢 谢! * * 1-* 三、对存储器和外接I/O口的绝对地址访问 例: #include #define com XBYTE[0x07ff] 那么后面程序com变量出现的地方,就是对地址为07ffH的外部RAM或I/O口进行访问。…

c 语言 timestamp,c中的时间戳,精度为毫秒

我对C编程比较陌生,而且我正在开展一个需要非常准确的项目;因此我尝试写一些东西来创建一个毫秒精度的时间戳.它似乎有效但我的问题是这种方式是否正确,还是有更简单的方法?这是我的代码:#include#includevoid wait(int milliseconds){clock_t start cl…

antd 左右滑动_如何使用reactjs创建可滑动的侧边栏

我正在尝试使用reactjs创建可滑动的侧边栏。但由于某些原因,这不会发生。我写的代码如下所示;如何使用reactjs创建可滑动的侧边栏Sidebar.jsimport React, { Component } from react;class Sidebar extends Component {render() {return (Start BootstrapDashboardS…

不思议迷宫c语言基础,不思议迷宫神龙收藏品一览

不思议迷宫神龙收藏品一览是9K9K小编柚子人为大家带来的,七龙珠召唤神龙作为游戏最为迷人的彩蛋之一,召唤神龙拿钻石作为众多玩家的首选目标,但神龙的收藏品你知道多少呢,下面不妨详细了解一下吧。神龙收藏品一览:无限…

shell181网格划分_复合材料SHELL181单元完全攻略

前言ANSYS程序中的SHELL181单元是用于复合材料层合板结构分析比较好的单元之一。原文在ANSYS程序的在线帮助中,这篇文章是它的译文,是我们从专业角度对原文的翻译。目的在于帮助那些英语水平不高,而且从事复合材料结构计算分析的技术人员能够…

c语言如何判断是否是子序列,leetcode392(判断子序列)--C语言实现

求&#xff1a;给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~ 500,000)&#xff0c;而 s 是个短字符串(长度 <100)。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩…

leetcode数组汇总_LeetCode刷题:前言

LeetCode刷题&#xff1a;前言前言作为一个对编程超级不通的小白&#xff0c;在2020年11月开始打算正式的刷LeetCode。&#xff08;PS&#xff1a;前面有刷过&#xff0c;但是都是随机&#xff0c;看心情乱刷的&#xff0c;刷完后也没有什么感觉&#xff0c;该不会的还是不会&a…

淮海工学院大一c语言期中试题,《C语言程序设计》期中考试试卷

《《C语言程序设计》期中考试试卷》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《《C语言程序设计》期中考试试卷(5页珍藏版)》请在人人文库网上搜索。1、淮 海 工 学 院10 11 学年 第 2 学期 C语言程序设计 期中考试试卷题号一二三四五总分得分单项选择题答题表123…

通信基站c语言,[转]2015年数学建模C题–基于无线通信基站的室内三维定位问题...

之前做的一题跟大家分享一下&#xff0c;实际该题数据出的有点问题(个人看法不喜勿喷)。这题主要是做基站定位的&#xff0c;方法主要是用的基于几何的方法。该题总共四题&#xff0c;由于只有测试case可以验证性能&#xff0c;非测试case的结果我就不放了在本题中&#xff0c;…

c语言fopen_s的用法,fopen和fopen_s用法的比较

参考&#xff1a;在定义FILE * fp 之后&#xff0c;fopen的用法是: fp fopen(filename,"w")。而对于fopen_s来说&#xff0c;还得定义另外一个变量errno_t err&#xff0c;然后err fopen_s(&fp,filename,"w")。返回值的话&#xff0c;对于fopen来说&…

php redis 投票_高可用Redis服务架构分析与搭建

HorstXuhttps://www.cnblogs.com/xuning/p/8464625.html基于内存的Redis应该是目前各种web开发业务中最为常用的key-value数据库了&#xff0c;我们经常在业务中用其存储用户登陆态&#xff08;Session存储&#xff09;&#xff0c;加速一些热数据的查询&#xff08;相比较mysq…

android studio 启动画面,Android Studio 利用Splash制作APP启动界面的方法

public class SplashActivity extends Activity {// private final int SPLASH_DISPLAY_LENGHT 2000; // 两秒后进入系统Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.…

android驱动测试,Android: 通过 cucumber 驱动 monkey 做稳定性测试

主要内容稳定性测试是什么Monkey 介绍自动化 Monkey稳定性测试是什么通过随机点击屏幕一段时间&#xff0c;看看 app 会不会奔溃&#xff0c;能不能维持正常运行。Monkey 介绍Monkey 是一个命令行工具&#xff0c;它可以运行在我们的模拟器或者设备当中。它可以发送一些伪随机(…

gradle 查看依赖类库版本_Android studio中查看依赖的第三方库的历史版本和最新版本...

在日常开发过程中&#xff0c;我们通过会依赖很多的第三方库项目。类似这样&#xff1a;dependencies {compile com.android.support:support-v4:24.2.1compile com.google.code.gson:gson:2.4compile com.lzy.net:okhttputils:1.7.0compile com.github.ybq:Android-SpinKit:1.…

set和map去重调用什么方法_【ES6】Set、Map

SetSet 是 ES6 提供给我们的构造函数&#xff0c;能够造出一种新的存储数据的结构特点&#xff1a;只有属性值没有属性名&#xff0c;成员值唯一用途&#xff1a;可以转成数组&#xff0c;其本身具备去重(自动去重)&#xff0c;交集&#xff0c;并集&#xff0c;差集的作用等参…