目录

  • 1、前言(废话)
  • 2、底部导航栏(TabBar)
  • 3、首页(home页面)
    • 3.1、首页导航栏
    • 3.2、首页网络数据的请求
    • 3.3、首页轮播图
    • 3.4、首页推荐模块
    • 3.5、首页本周流行模块
    • 3.6、首页商品展示模块
      • 3.6.1、展示模块的TabControl
      • 3.6.2、展示模块的数据请求与划分
      • 3.6.3、数据的展示结构
      • 3.6.4、TabControl控制不同类型数据展示
      • 3.6.5、better-scroll进行对滚动重构
      • 3.6.6、首页回到顶部小按钮
      • 3.6.7、首页上拉加载更多
      • 3.6.8、home组件离开时记录状态和位置
  • 4、详情页
    • 4.1、跳转到详情页并且携带商品id
    • 4.2、详情页导航栏
    • 4.3、详情页数据请求与存储
    • 4.4、详情页轮播图
    • 4.5、详情页基本信息展示
    • 4.6、导入scroll组件
    • 4.7、标题与内容的联动效果
    • 4.8、详情页底部工具栏
    • 4.9、加入回到顶部的按钮
  • 5、购物车页面
    • 5.1、将商品添加到购物车
    • 5.2、购物车导航栏
    • 5.3、商品列表展示
    • 5.4、底部工具栏
    • 5.5、Toast(吐司)插件模式
  • 6、一些优化的方面
    • 6.1、解决移动端点击300ms延迟
    • 6.2、图片懒加载
  • 7、大结局

1、前言(废话)

随着codewhy的vue2.0学习结束,想着做个项目练练手便跟着老师的视频项目学习一下思路。本篇记录一下项目的大概思路。
首先还是来划分一下目录结构,这样做项目会格外清晰,不至于找不到自己写的都是个啥。(vuecli3.0为例)
在脚手架自动搭建好之后,大目录分为:

1、node_modules文件夹(不用细究,npm install自动生成,跟node有关)
2、public文件夹(相当于vue2.0的static文件夹,一般是.html,.icno之类的文件)
3、src文件夹(这就是我们写源码的主要部分了)。接下来我们重点分析src文件夹里的目录结构。(1)assets文件夹是资源文件夹,主要放图片资源和css文件资源。(2)common文件夹主要为混入(mixin)与数据处理的函数。(3)components文件夹主要是组件所放位置。common文件夹是可以通用的组件,就是别人项目也能用。content文件夹是放具有本项目特色的组件。(4)network文件夹是存放网络请求相关的函数。(5)router则是该项目路由配置文件的项目。(6)store文件夹是vuex用来管理各组件公共变量的。(7)views文件夹则是项目各个页面进行分类编码,属于该页面的个性化组件也可以定义在该文件夹。(8)APP.vue就是进行组件展示和渲染。(9)main.js就是项目入口文件。相当于vue的入口,系统进入vue中,先起作用的就是main. js,通过main. js内的代码引导系统下一步怎么做。
4、各种配置文件

配置别名,避免重复写多余路径。

module.exports = {configureWebpack: {resolve: {alias: {'assets': '@/assets','common': '@/common','components': '@/components','network': '@/network','router': '@/router'}}}}

2、底部导航栏(TabBar)

废话不多说,直接进入正题。做这类移动商城类项目,底部导航栏写好,整个项目的框架也就大致搭建完成。
1、封装一个单独的TabBar组件,让TabBar位于底部,并且设置相关的样式(就是位于底部就可以)。
在这里需要引入一些公共的css样式文件,目前在APP.vue的style中通过@import处理。

@import url('./assets/css/base.css');

通过display:fixed布局到页面底部,然后就是弄背景色调阴影。
2、为了实现重用性和个性化,自定义TabBarItem,使其可以传入图片和文字。这就需要slot插槽的帮助。
定义一定数量的插槽,使用flex布局进行布局,在每个插槽外层包装div,用于设置插槽的样式。且每个插槽提供图片和文字两部分。
在TabBarItem里定义三个插槽,前两个是具有选择关系的图片插槽,最后一个文字插槽。


然后对该项目配置路由,在router文件夹下配置每个组件的路由,然后对TabBarItem进行点击事件,根据项目需要配置路由,

this. r o u t e r . r e p l a c e ( t h i s . p a t h ) (不可返回)或者 t h i s . router.replace(this.path)(不可返回) 或者 this. router.replace(this.path)(不可返回)或者this.router.push(this.path)(可返回)

这样TabBar这一部分算基本结束。

3、首页(home页面)

3.1、首页导航栏

鉴于该项目多处都用到导航栏的部分,所以在此处封装一个NavBar的组件。考虑到导航栏的个性化,同时放三个具名插槽,为左中右三部分。同时注意,为了给插槽调整样式,但如果直接给slot添加class类名,以后会出现很多奇奇怪怪的报错,所以在这里用一个div套一个slot,然后进行样式的调整。

3.2、首页网络数据的请求

目前vue中经常使用的网络请求是axios,但难免以后网络请求淘汰axios,而选择一个新的网络请求库。为了以后修改方便以及方便给axios修改一些默认配置,在这里选择二次封装网络请求。
在network文件夹,新建request.js(随便取)文件,对axios进行二次封装。(接口别期待找到了,需要找老师,10yuan体验)因为请求回来的数据很多,也很乱。拦截处理,返回有用的data里面的数据。

新建home.js,以后与home网络请求相关的都放这。(美观,也方便管理)

把请求下来的数据放在各个组件的data中保存,避免垃圾处理回收。

getHomeMultidata() {getHomeMultidata().then(res => {// console.log(res);this.banners = res.data.banner.list;this.recommends = res.data.recommend.list;});},

3.3、首页轮播图

这里老师有写好的,可以直接拿来用(但有一定的bug照片第一次刷新的时候,有时候出现,有时候不出现,很无语),也可以用现成的ui库(比如vant库)。但我还是建议手撸一遍源码,保证自己会写的前提下,再使用组件库。在这里,我用的是vant组件库,只把轮播图数据传进去即可。

3.4、首页推荐模块

这一部分很简单,继续封装成一个属于home的独立组件,然后div包装,flex布局,因为图片和文字放在一个超链接中,后面的页面直接用的人家的连接,咱也不用写,也不用管。

3.5、首页本周流行模块

老师懒省事,就是一张图片放那了,自己改改样式和布局,弄成一个组件即可。

3.6、首页商品展示模块

兄弟萌,它来了它来了,它迈着嚣张的步子走来了——better-scroll(bug-scroll,可能是我菜,反正用的不舒服)。

3.6.1、展示模块的TabControl

由于该项目,这种控制模块长得都一样,就文字不一样。这里就不采用插槽而是固定格式三个位置,父与子传递数据,传入文字数组即可。

吸顶效果: 老师用了一个很巧妙的方式,放两个TabControl组件,一个紧跟导航栏,一个放在推荐模块下,通过实时位置与TabControl组件位置进行比较,小于第二个TabControl组件高度,第二个出现,大于TabControl组件高度,第一个出现。

3.6.2、展示模块的数据请求与划分

对数据请求划分三类,流行,新款,精选。每一类按页进行划分与展示。

 goods: {pop: { page: 0, list: [] },new: { page: 0, list: [] },sell: { page: 0, list: [] }}

在home.js对展示数据进行按页请求


export function getHomeGoods(type,page) {return request({url:'/home/data',params:{type,page}})
}

在vue的生命周期函数created,一旦开始创建,就需要申请数据。

用于请求更多的数据

3.6.3、数据的展示结构

然后封装GoodsList和GoodsListItem两个组件。把对应的数据传进去进行展示,然后调样式。

GoodsList组件:

GoodsListItem组件

3.6.4、TabControl控制不同类型数据展示

在TabControl组件的点击事件中,发送事件,暴露点击的选项参数。然后在home组件对参数进行处理。

tabClick(index) {switch (index) {case 0:this.currenttype = "pop";break;case 1:this.currenttype = "new";break;case 2:this.currenttype = "sell";break;}

然后通过currenttype这个变量把对应的数据传给goodList。

<goods-list :goods="showGoods"></goods-list>computed: {showGoods() {return this.goods[this.currenttype].list;}}

从而实现TabControl控制不同类型数据展示。
但有一个小问题,就是两个TabControl状态无法保持一致。在TabControl的点击事件中保证两个选项相同即可。

this.$refs.tabControl1.currentIndex = index;
this.$refs.tabControl2.currentIndex = index;

3.6.5、better-scroll进行对滚动重构

2.0版本的better-scroll我个人感觉不是太好用,这里采用1.13.2版本的。通过npm install @better-scroll@1.13.2 --save进行局部安装。同样为了避免以后滚动更换库,对better-scroll封装成一个组件scroll。

<template><div ref="wrapper"><div class="content"><slot></slot></div></div>
</template>import BScroll from "better-scroll";export default {name: "myScroll",data() {return {scroll: null,message: "哈哈哈",};},props: {probeType: {type: Number,default: 0,},pullUpLoad: {type: Boolean,default: false}},//之前是moutedmounted() {// 1.创建BScroll对象this.scroll = new BScroll(this.$refs.wrapper, {observeDOM: true,observeImage: true,click: true,/*1不可以监听2 监听滚动的位置,惯性不记录3监听滚动的位置,惯性记录*/probeType: this.probeType,pullUpLoad: this.pullUpLoad,mouseWheel: true, //开启鼠标滚轮disableMouse: false, //启用鼠标拖动disableTouch: false, //启用手指触摸});//监听滚动的位置if (this.probeType === 2 || this.probeType === 3) {this.scroll.on("scroll", (position) => {this.$emit("scroll", position);});}if (this.pullUpLoad) {this.scroll.on("pullingUp", () => {this.$emit("pullingUp");})}

绿色部分是包装器,也称为父容器,具有固定的高度。黄色部分是内容,它是父容器的第一个子元素,其高度会随着内容的大小而增长。然后,当内容的高度不超过父容器的高度时,内容不会滚动。一旦超过,内容可以滚动。这就是 BetterScroll 的原理。

所以我们在使用better-scroll的时候,一定要对wrapper这个div设置一个固定高度。设置固定高度有两种办法。

或者

.content {height:calc(100% - 44px - 49px);overflow:hidden;margin-top:44px;
}

但在这里我们往往会出现无法滚动的bug,这是因为对于better-scroll如果您的内容元素包含非固定大小的图像,则必须调用该refresh()方法以确保在加载图像后正确计算高度。
这里有一个小tips,在vue中可以用@load来监听是否图片加载完成,后面可以绑定一个函数<img v-lazy="showImage" alt="" @load="imageLoad">


通过refresh()重新计算一下高度即可。

3.6.6、首页回到顶部小按钮

效果:当高度下降到一定位置右下方出现一个小按钮,点击可以回到顶部。

继续封装啊,兄弟们,封装一个backTop的组件,里面设置样式,通过fixed设置布局,使其固定在页面上。正常情况点击backtop小组件会调用this.$refs.scroll.scrollTo(x坐标,y坐标,返回用时毫秒);返回顶部,然而scroll和backtop都是home的一个组件彼此互相通信不太方便(当然可以使用事件总线 $ bus),在这时候直接选择对组件进行click监听,但一般情况click是无法监听组件的,这就用到了v-on的修饰符——.native:监听组件根元素的原生事件。然后通过this.$refs.scroll拿到scroll对象,最后返回顶部。
而想实现backTop在一定高度消失和出现,就需要用到better-scroll内部的一个方法。

 if (this.probeType === 2 || this.probeType === 3) {this.scroll.on("scroll", (position) => {this.$emit("scroll", position);});}

将实时位置发送给home组件,通过this.tapOffsetTop = this.$refs.tabControl2.$el.offsetTop; 获取组件的位置,从而与实时位置进行比较,然后通过v-show对其进行展示。

3.6.7、首页上拉加载更多

同样借用了better-scroll里的一个方法。为实现个性化,有的需要下拉加载更多,有的不需要,根据父元素传的pullUpLoad决定

 if (this.pullUpLoad) {this.scroll.on("pullingUp", () => {this.$emit("pullingUp");})}

一旦到底,向home发送一个pullingUp事件,与loadMore进行绑定(自定义)。

loadMore() {this.getHomeGoods(this.currenttype);},getHomeGoods(type) {const page = this.goods[type].page + 1;getHomeGoods(type, page).then(res => {this.goods[type].list.push(...res.data.list);this.goods[type].page += 1;//完成上拉加载更多,保障下一次下拉加载更多this.$refs.scroll.finishPullUp();});}

3.6.8、home组件离开时记录状态和位置

通常保存历史状态用keep-alive即可,详情页

<keep-alive exclude="Detail"><router-view /></keep-alive>

但幸好有“bug-scroll”,导致出现状态无法保存。这里就要借用vue生命周期钩子函数之activated和deactivated,在组件离开时,记录y的位置,当组件回来时,直接跳转到离开的位置(但注意不要设置为0),这里离开的位置可以通过this.$refs.scroll.scroll.y来获取。当回归后,一般强制刷新一下。

activated() {this.$refs.scroll.scrollTo(0,this.saveY,1);this.$refs.scroll.refresh();},deactivated(){this.saveY = this.$refs.scroll.scroll.y;},

4、详情页

4.1、跳转到详情页并且携带商品id

首先需要配置详情页detail的路由,保证可以进行跳转。

 {path: '/detail/:id',component: Detail}

因为需要传参数,此处采用动态路由。

this.$router.push('/detail/' + this.goodsItem.iid);

但也可以用query方法。

this.$router.push({path: '/detail',
query:{id: this.goodsItem.iid}
})

4.2、详情页导航栏

因为此处导航栏没首页那么简单,所以继续封。对居中的插槽,和左边插槽进行编写。

<div class="product-detail-nav-bar"><nav-bar><div @click="backHomePage" class="back-img" slot="left"><img alt="" src="@/assets/img/common/back.svg" /></div><div class="title" slot="center"><span:class="{ active: index === currentIndex }":key="index"@click="titleItemClick(index)"class="title-item"v-for="(item, index) in titles">{{ item }}</span></div></nav-bar></div>

4.3、详情页数据请求与存储

商品的详细信息:

import { request } from "./request";export function getDetail(iid){return request({url:'/detail',params:{iid}})
}

将数据以类的方式分类保存。

export class Goods {constructor(itemInfo, columns, services) {this.title = itemInfo.title;this.desc = itemInfo.desc;this.newPrice = itemInfo.price;this.lowNowPrice = itemInfo.lowNowPrice;this.oldPrice = itemInfo.oldPrice;this.discount = itemInfo.discountDesc;this.discountBgColor = itemInfo.discountBgColor;this.columns = columns;this.services = services;this.relPrice = itemInfo.lowNowPrice;}
}// 店铺数据
export class Shop {constructor(shopInfo) {this.logo = shopInfo.shopLogo;this.name = shopInfo.name;this.fans = shopInfo.cFans;this.sells = shopInfo.cSells;this.score = shopInfo.score;this.goodsCount = shopInfo.cGoods;this.shopurl = shopInfo.allGoodsUrl;}
}// 尺寸数据
export class GoodsParams {constructor(info, rule) {// 注: images可能没有值(某些商品有值, 某些没有值)this.image = info.images ? info.images[0] : "";this.infos = info.set;this.sizes = rule.tables;}
}

然后将数据进行保存。

//根据iid请求所需要的数据getDetail(this.iid).then(res => {console.log(res);const data = res.result;//获取轮播图数据this.topImages = data.itemInfo.topImages;//获取商品信息this.goods = new Goods(data.itemInfo, data.columns, data.shopInfo.services);//获取店铺信息this.shop = new Shop(data.shopInfo);//获取商品图片详细信息this.detailInfo = data.detailInfo;//获取参数信息this.paramInfo = new GoodsParams(data.itemParams.info, data.itemParams.rule);// 获取评论数据if (data.rate.cRate !== 0) {this.commentInfo = data.rate.list[0] || {};}}),getRecommend().then(res => {console.log(res);this.recommend = res.data.list})

4.4、详情页轮播图

这里老师的swiper封装的组件有问题,在这里我用的是vant组件库,把上述请求到的topImages数据传到轮播图组件,然后进行渲染。

<detail-swiper :top-images="topImages" class="detail-set-scroll"></detail-swiper>
<van-swipe :autoplay="2500" indicator-color="#ff0000" class="swiper-list" duration="400"><van-swipe-item :key="index" v-for="(item, index) in topImages"><img :src="item" @load="swiperLoad" alt="" /></van-swipe-item></van-swipe>

4.5、详情页基本信息展示

这一部分,包括商品的基本信息,店铺信息,商品详情数据,商品参数信息,商品推荐信息的展示。都是一个思路,封装组件,把分好类的数据分别传入,改样式展现数据。

4.6、导入scroll组件

把已经封装好的scroll组件导入,注意一定要给scroll一个固定高度。

.scroll-height {position: absolute;top: 44px;right: 0;bottom: 50px;left: 0;overflow: hidden;width: 100%;background-color: white;
}

4.7、标题与内容的联动效果

点击标题滚动到相应位置:
我们可以通过detail中监听标题的点击,获取index,然后在点击事件中滚动到对应的内容,所以如何获取各部分的内容成为了难题。

  • 如何正确获取各部分内容的offsetTop
  • 1、在created中,不可以,此时的dom元素都没挂载,this.$refs.comment.$el根本不存在。
  • 2、在mounted中,不可以,此时仅仅简单挂载dom元素,还无法获取数据。
  • 3、在updated中,不可以,获取到数据的回调也不行,dom还没渲染完。
  • 4、在$nextTick中,不可以,dom渲染完了,但图片的高度可能无法计算在内。
  • 5、最终选择,在图片加载完成的监听中,进行赋值,因为频率过高,选择防抖来进行处理。
created(){this.getThemeTopY = debounce(() => {this.themeTopYs = [];this.themeTopYs.push(0);this.themeTopYs.push(this.$refs.params.$el.offsetTop);this.themeTopYs.push(this.$refs.comment.$el.offsetTop);this.themeTopYs.push(this.$refs.recommend.$el.offsetTop);this.themeTopYs.push(Number.MAX_VALUE)console.log(this.themeTopYs);}, 250)},
methods:{imgLoad() {this.$refs.scroll.refresh();this.getThemeTopY();},
}

Number.MAX_VALUE是极大值的意思。

滚动内容,标题相应选中:

contentScroll(position) {this.isShowBackTop = (-position.y) > 1000;const positionY = -position.y;const length = this.themeTopYs.length;for (let i = 0; i < length - 1; i++) {//这里的i是string类型// if (this.currentIndex !== i && (i < length - 1 && positionY >= this.themeTopYs[i] && positionY < this.themeTopYs[i + 1]) ||//   (i === length - 1 && positionY > this.themeTopYs[i])) {//   this.currentIndex = i;//   this.$refs.nav.currentIndex = this.currentIndex;// }if (this.currentIndex !== i && (positionY >= this.themeTopYs[i] && positionY < this.themeTopYs[i + 1])) {this.currentIndex = i;this.$refs.nav.currentIndex = this.currentIndex;}}},

4.8、详情页底部工具栏

在这里我用的是vant组件库,继续封装。

<div class="bottom-bar"><van-goods-action><van-goods-action-icon icon="chat-o" text="客服" /><!-- :badge="cartLength" --><van-goods-action-icon icon="shop-o" text="店铺" /><van-goods-action-icon :color="isShouCang ? '#ff5000' : '#000000'" :icon="isShouCang ? 'star' : 'star-o'":text="isShouCang ? '已收藏' : '收藏'" @click="starClick" /><van-goods-action-button @click="addToCart" text="加入购物车" type="warning" /><van-goods-action-button @click="$router.push('/shopcart')" text="立即购买" type="danger" /></van-goods-action></div>

4.9、加入回到顶部的按钮

因为backTop组件已经封装好,在其他很多组件都会复用,代码格式都一样,为了避免代码的重复性,这里使用mixin混入。

export const backTopMixin = {components:{backTop},data(){return {isShowBackTop: false}},methods:{backClick() {this.$refs.scroll.scrollTo(0, 0, 500);},}
}

5、购物车页面

5.1、将商品添加到购物车

通过监听底部导航栏加入购物车选项的监听,来把数据传给购物车。

addToCart(){//获取购物车需要获取的信息const product = {};product.image = this.topImages[0];product.title = this.goods.title;product.desc = this.goods.desc;product.price = this.goods.relPrice;product.iid = this.iid;//将商品添加到购物车//this.$store.commit('addCart',product)this.$store.dispatch("addCart",product).then(res => {this.$toast.show(res);})}

由于详情页的子组件与购物车组件不方便传递,一般使用vuex来进行管理。

export default {addCounter(state,payload){payload.count++;},addToCart(state,payload){payload.checked = false;state.cartList.push(payload);},clearCarList(state) {// 判断选中哪些数据,过滤没选中的数组返回一个新数组即可let result = state.cartList.filter(item => item.checked !== true);if (result.length === 0) {localStorage.removeItem("cartList");state.cartList = [];} else {state.cartList = result;localStorage.setItem("cartList", JSON.stringify(state.cartList));}},setCartList(state, data) {state.cartList = data;}
}

5.2、购物车导航栏

有一个知识点需要注意,就是…mapGetters。

computed: {//使用mapGetters可以让getters中的方法自动转换到计算属性一共两种用法//不起别名//...mapGetters(['cartLength','cartList']),//起别名...mapGetters({length: 'cartLength',list: 'cartList'})}

5.3、商品列表展示

同之前,封装,调样式。

5.4、底部工具栏

计算总价钱

totalPrice() {return this.$store.state.cartList.filter(item => item.checked).reduce((preValue, item) => preValue += item.price * item.count, 0).toFixed(2);},

全选的双向绑定
通过判断每一个添加的商品的checked属性,如果全部选中,则全选框选中。点击全选框,则选中商品的checked属性与全选框的属性保持一致。

5.5、Toast(吐司)插件模式

这里同样先弄一个Toast组件,但不是常规的导入了,而是要把他弄成一个插件。第一步先封装一个Toast组件。

然后建立Toast.js文件,保证main.js导入的时候,Toast.js也可以导入。

import toast from './components/common/toast'Vue.use(toast);

在Toast.js内部,对安装函数进行重构。

import Toast from "./Toast.vue";const obj = {}// 将对象安装到Vue上
obj.install = function (Vue) {// 1.创建组件构造器const toastConstructor = Vue.extend(Toast);// 2.new的方式,根据组件构造器,可以创建出来一个组件对象const toast = new toastConstructor();// 3.将组件对象手动挂载到某个元素上toast.$mount(document.createElement("div"));// 4.myToast.$el就已经挂载到上面创建的div了,然后将div挂载到body上即可document.body.appendChild(toast.$el);// 最后将myToast挂载到Vue的原型上Vue.prototype.$toast = toast;
}export default obj

6、一些优化的方面

6.1、解决移动端点击300ms延迟

进行安装

npm install fastclick --save

进行使用,在main.js文件里。

FastClick.attach(document.body);

6.2、图片懒加载

图片懒加载就是当图片出现在视图再进行加载。

Lazyload官方文档

官方讲的很明白。这里最简单的使用
安装


$ npm i vue-lazyload -S

导入

import VueLazyload from 'vue-lazyload'Vue.use(Lazyload, {// 未加载的占位图片loading: require("@/assets/img/common/placeholder.png")
})

7、大结局

本来准备随便写写的,结果洋洋洒洒写了这么多。做这个项目bug不少,但是根据弹幕还是可以解决的,大部分老师都带着解决。注意弹幕!注意弹幕!注意弹幕!另外,还有两个部分,老师没做,所以不适合放简历上,但有兴趣的大佬可以补了。此文章供个人以后的移动电商的思路加上第一次写,可能有很多部分写的不清楚,实在抱歉!

codewhy-vue2.0移动电商项目回顾相关推荐

  1. vue尚品汇商城项目-day00【项目介绍:此项目是基于vue2的前台电商项目和后台管理系统】

    文章目录 本人其他相关文章链接 项目介绍:此项目是基于vue2的前台电商项目和后台管理系统 此项目为在线电商Web App (SPA) 包括首页, 搜索列表, 商品详情, 购物车, 订单, 支付, 用 ...

  2. 项目笔记-基于VUE2.0的电商后台管理系统(一)

    前端项目初始化步骤 ①安装vue脚手架 ②通过vue脚手架创建项目 ③配置vue路由 ④配置elementUI组件库 ⑤配置axios库 ⑥初始化git 第一部分:登录界面 首先,在登录界面设置一个该 ...

  3. 小兔鲜儿Vue3.0前端电商项目实战

    小兔鲜儿Vue3.0实现了电商平台主线业务功能,电商首页.一级分类.二级分类.商品详情.购物车.结算.支付.个人中心.订单管理.订单详情. 项目采用前后端分离模式,前台使用了VUE3.0技术栈构建,自 ...

  4. 基于 Serverless 无服务器(0成本),B2C电商项目开源了

    用云电商 uniCloud 版本 Usecloud.usemall.b2c 完整的业务流程数字化电商项目,JavaScript 解决前端后端.数据库的全栈开发 uniCloud serverless  ...

  5. 大型电商项目3.0实战+支付宝、微信支付项目实战

    须知:视频来源网络,侵权请联系删除! 大型电商项目3.0实战 获取方式 扫描下面二维码回复:A110 支付宝.微信支付项目实战 获取方式 扫描下面二维码回复:A106

  6. 前端电商项目实战,如何从 0 开始创造一个【考拉海购官网】?( 共6节教程 )

    文章目录 声明 一,关于页面还原度效果比较 二,第一组演示图是 考拉海购官网的 三,第二组演示图是 本次教程从0开发的 四,教程目录(共6节) 五,全部代码下载地址 新手提示 (1)如何从github ...

  7. 尚硅谷2020微服务分布式电商项目《谷粒商城》学习笔记

    尚硅谷2020微服务分布式电商项目<谷粒商城> 项目简介 资料 百度云 链接:https://pan.baidu.com/s/1eGCTi6pLtKbDCwBs-zCOzQ 提取码:1pm ...

  8. SpringBoot+SpringCloud+Mybatis+Vue 电商项目实战,附视频+源码+文档,包含所有主流技术栈。...

    大家好,我是树哥. 今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主 ...

  9. SpringBoot+SpringCloud+Mybatis+Vue电商项目实战,附视频+源码+文档,包含所有主流技术栈...

    今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主要功能.难点功能以及 ...

最新文章

  1. win7怎么配置程序服务器错误日志文件,win7怎么配置程序服务器
  2. XCTF_Web_新手练习区:weak_auth
  3. 如何修复 SAP UI5 aggregation with cardinality 0..1 相关的错误消息
  4. 主成分分析法_主成分分析法在地震学领域的新应用
  5. solr hdfs solr.in.sh
  6. php this db get,php – Codeigniter $this- db- get(),如何返回特定行的值?
  7. Linux C基础笔记(2)
  8. 利用子查询解决复杂sql问题
  9. php yyuc框架,求一份YYUC框架文件和帮助文档
  10. De4Dot+Reflector 支持多种反混淆
  11. php微信发送客服消息,微信公众号利用客服消息和模板消息实现微信群发
  12. Adaptable and Adaptive Hypermedia Systems
  13. XMPP 客户端和服务端
  14. java在线答题系统,上岸蚂蚁金服!
  15. 时间序列分析-----1---简介
  16. 兼职项目分享,在家就可以做的八个副业项目,利用业余时间增加收入吧
  17. 徇私舞弊不移交刑事案件罪
  18. JDK7-HashMap源码解析
  19. jquery点击获取当前图片地址
  20. 综合布线---关于线缆的一些小知识(1)

热门文章

  1. Vue路由 传参几种方式
  2. linux卸载桌面Ubuntu,Ubuntu 10.04 安装卸载KDE桌面之折腾记
  3. 【CSS】1372- 使用 CSS 制作动画的 12 条原则
  4. GDUFS 2017信息学院程序设计新手赛(正式赛)题解
  5. 【转载】Discuz!NT企业版之Sphinx全文搜索
  6. Linux如何查看LV的容量情况,LVM 逻辑卷管理器-增大LV容量
  7. 推荐14种新兴专业 人才稀缺前景非常好
  8. 深度学习TensorFlow环境配置及遗留的问题(cudatoolkit版本,TensorFlow版本)(四)
  9. java json 嵌套解析_Java 嵌套解析 json
  10. 计算机毕业设计Java游戏资讯网站(源码+系统+mysql数据库+Lw文档)