滚动行为

在页面滚动到底部点击detail的商品图片之后,用router-link跳转,同时请求的数据也要通过三连环来实现

<router-link :to="`/detail/${goods.id}`"><img :src="goods.defaultImg" />
</router-link>

底部点击图片之后,跳转之后的页面的滚动条也会停留在上个页面的位置,为了阻止这个行为,vue-router的官方文档中专门设有一个属性(这一段放在router里面)

//滚动行为scrollBehavior(to, from, savedPosition) {//返回的这个y=0,代表的滚动条在最上方return { y: 0 };},

api的请求地址为 /api/item/{ skuId }     请求方式为 GET       携带的参数名称为 skuId

get请求携带参数,同时skuId需要根据点击的商品的数据id获取

在detail里面派发数据,但是要传递参数,参数为路由中params的数据

mounted() {this.$store.dispatch('detailList',this.$route.params.skuId)
},

在action中也需要这个数据

const actions = {async detailList({commit},skuId){const res = await reqDetailList(skuId)// console.log(res)if(res.code == 200){commit('DETAILLIST',res.data)}},
}

mutations接收

const mutations = {DETAILLIST(state,detailList){state.detailList = detailList},
}

state存储detailList的类型为obj

const state = {detailList:{}
}

开始在静态组件中绑定数据

点击排他

在遍历数据的过程中,有一个2个数组中分别有2个元素,当点击其中一个元素时,需要让边框变成绿色,一般想到了:class和@click两个结合,但是这里需要用到排他思想,吧点击的那个按钮的的isChecked变成1,其他没有点击的变成0,这里需要传两个参数,一个是点击当前的小数据,一个是那两个数组的数据,因为这两个参数里面都有isChecked这个属性

<!-- 把颜色参数遍历出来 -->
<dl v-for="(item,index) in spuSaleAttrList" :key="item.id"><dt class="title">{{item.saleAttrName}}</dt><!-- 把具体颜色遍历出来 --><dd changepirce="0" :class="{active:item1.isChecked== '1'}" v-for="(item1,index1) in item.spuSaleAttrValueList" :key="item1.id" @click="changeActive(item1,item.spuSaleAttrValueList)">{{item1.saleAttrValueName}}</dd>
</dl>
methods:{changeActive(item1,item){// console.log(item1,item)item.forEach(isIt =>{isIt.isChecked = '0'})item1.isChecked = '1'
},

小轮播图

还是用swiper这个组件,遍历出来图片之后,在原来的代码中初始化swiper,就可以用了

当点击小轮播图(ImageList)中的图片后(zoom)中的图片也要变化,这个也是兄弟组件通信,还是用事件总线$bus

在ImageList中获取点击到图片的索引,传给zoom中

ImageList

methods:{getIndex(index){this.currentIndex = index// 通知兄弟组件,当前的索引值this.$bus.$emit('changeIndex',this.currentIndex)}}

zoom

mounted() {//全局事件总线,挂载到mounted中this.$bus.$on('changeIndex', (currentIndex) => {this.index = currentIndex})}

放大镜

<div class="spec-preview">// 最底下的图<img :src="objImg.imgUrl" />// 鼠标移动的事件<div class="event" @mousemove="handler"></div>// 放大之后的图<div class="big" ><img :src="objImg.imgUrl" ref="big" /></div>// 遮罩层<div class="mask" ref="mask"></div></div>

动态绑定图片之后,用@mousemove的事件来获得鼠标移动的偏移量,同时让遮罩层的可以在底层图中随着鼠标移动

methods: {handler(event) {let mask = this.$refs.masklet big = this.$refs.biglet left = event.offsetX - mask.offsetWidth / 2let top = event.offsetY - mask.offsetHeight / 2if (left <= 0) {left = 0}if (left >= mask.offsetWidth) {left = mask.offsetWidth}if (top <= 0) {top = 0}if (top >= mask.offsetHeight) {top = mask.offsetHeight}mask.style.left = left + 'px'mask.style.top = top + 'px'big.style.top = -2 * top + 'px'big.style.left = -2 * left + 'px'}},

input中动态绑定数据,同时只限制输入值的类型为number

<div class="controls"><input autocomplete="off" class="itxt" v-model.number="inputNum" @input="getInputNum"><a href="javascript:" class="plus" @click="inputNum++">+</a><a href="javascript:" class="mins" @click="inputNum>1?inputNum--:inputNum==1">-</a>
</div>

直接v-model双向绑定,.number可以限制类型,但是不能限制所有的比如.或者在d12ssa,在input事件中限制类型,用replace和正则来替换不正确的字符

// 用正则,文本框中只能输入数字
            this.inputNum = this.inputNum.replace(/[^\d]/g,'')

getInputNum(inputNum){// 用正则,文本框中只能输入数字this.inputNum = this.inputNum.replace(/[^\d]/g,'');
},

点击加入购物车路由跳转

判断选择的参数是否正确

发请求---将产品加入到数据库(通知服务器)
当前这里是派发一个action,向服务器发请求,判断加入购物车是成功还是失败

传入skuId和skuNum

let res = await this.$store.dispatch('addToCartList',{skuId:this.$route.params.skuId,inputNum:this.inputNum})

在store中接收派发

这里是传递了两个参数,需要包起来,用{},然后通过解构

async addToCartList({commit},{skuId,inputNum}){// 加入购物车的解构// 因为购物车请求数据之后并没有返回数据// 服务器只需要知道这次请求的code是否为200,也就是是否请求成功// 因此不需要三连环const res = await reqAddToCart(skuId,inputNum)if(res.code == 200){// return Promise.resolve('成功')return 'OK'}else{return Promise.reject(new Error('false'))}// return Promise.reject(new Error('false'))}

然后用try、catch捕获异常

async addCart(){// 1.发请求---将产品加入到数据库(通知服务器)// 当前这里是派发一个action,向服务器发请求,判断加入购物车是成功还是失败// let res = await this.$store.dispatch('addToCartList',{skuId:this.$route.params.skuId,inputNum:this.inputNum})// console.log(res)try{await this.$store.dispatch('addToCartList',{skuId:this.$route.params.skuId,inputNum:this.inputNum})// 路由跳转// 在路由跳转的时候还需要把产品的信息带给下一级的路由组件// 一些简单的数据inputNum,通过query的形式给路由组件传递出去// 产品信息的数据【比较复杂:skuInfo】,通过会话存储window.sessionStorage.setItem('skuinfo',JSON.stringify(this.skuInfo))this.$router.push({path:'/addcartsuccess',query:{skuNum:this.inputNum,skuInfo:this.skuInfo}})// this.$bus.$emit('getChange',this.getItem)// console.log(this.getItem,'dwadaw')}catch(error){alert(error.message)}}

传递detail的数据给addcartsuccess

<div class="right-info"><p class="title">{{skuinfo.skuName}}</p><p class="attr">数量:{{$route.query.skuNum}}</p></div>
computed:{skuinfo(){return JSON.parse(window.sessionStorage.getItem('skuinfo'))}       },

本地存储和会话存储

浏览器存储功能:HTML5中新增的,本地存储和会话存储

本地存储:持久化的-----------5M

会话存储:并非持久------------会话结束就消失(关闭浏览器)

本地存储 | 对话存储 ,一般存储字符串,如果传递的数据是对象,需要把对象转化为字符串

JSON.stringify 讲JSON对象转化为JSON字符串

JSON.parse 将JSON字符串转化为JSON对象

当在detail中加入购物车后需要加入一个uuid,需要本地存储

uuid时npm自带的一个api

使用uuid

新建一个utils的目录,存放

import { v4 as uuidv4 } from 'uuid';
// 生成一个随机字符串,且每次执行不能发生变化,游客身份持久存储
export function getUUID(){// 先从本地存储获取uuid(看一下本地存储里面是否有)let uuid_token = localStorage.getItem('UUIDTOKEN')// 如果没有if(!uuid_token){// 生成游客临时身份uuid_token = uuidv4()// 本地存储一次localStorage.setItem('UUIDTOKEN',uuid_token)}return uuid_token
}

这里是会话存储,存储当前你加入了购物车的商品

在request.js拦截器里面加入

if(store.state.detail.uuid_token){//请求头添加一个字段(userTempId):和后台老师商量好了config.headers.userTempId = store.state.detail.uuid_token;}

在store的detail.js中使用

import {getUUID} from '@/utils/uuid_token.js'
const state = {detailList:{},// 游客临时身份uuid_token:getUUID()
}

购物车

添加购物车页面

用router-link跳转页面

跳转之后,获取到会话存储的商品列表

<div class="right-gocart"><a class="sui-btn btn-xlarge" @click="$router.go(-1)">查看商品详情</a><!-- <a href="javascript:" >去购物车结算 > </a> --><router-link to="/shopcart">去购物车结算 </router-link></div>

购物车页面

购物车的静态页面

先三连环获取购物车列表

购物车中的skuNum需要跟store中的数据一样,所以也需要发请求

skuNum由3个东西控制,分别是+、-和input,这三个参数在发请求时需要辨别出来,于是选择了传参,当实参不同时,写入的功能也不同

用+-和input控制数量

<li class="cart-list-con5"><a @click="getskuNum('sub',-1,item)" class="mins">-</a><input autocomplete="off" type="text" @change="getskuNum('getinput',$event.target.value,item)":value="item.skuNum" minnum="1" class="itxt"><a @click="getskuNum('add',1,item)" class="plus">+</a>
</li>

注意这里的num是变化量

async getskuNum(type, num, item) {// type:为了区分这三个元素// disNum形参: 变化量(+1)  -变化量(-1) input最终的个数// item:哪一个产品(身上有id)// 向服务器发请求,修改数量// console.log(type,num,item)switch (type) {case 'sub':num = item.skuNum >= 2 ? -1 : 0breakcase 'add':num = 1breakcase 'getinput':if (isNaN(num) || num < 0) {num = 0} else {num = parseInt(num) - item.skuNum}break}// 派发actionstry {let res = await this.$store.dispatch('addToCartList', {skuId: item.skuId,inputNum: num})this.getData()} catch (error) {alert(error.message)//TODO handle the exception}},

checkbox同样如此

需要获取到skuid和ischecked的值

三连环传入(item,$event),再重新发请求

<li class="cart-list-con5"><a @click="getskuNum('sub',-1,item)" class="mins">-</a><input autocomplete="off" type="text" @change="getskuNum('getinput',$event.target.value,item)":value="item.skuNum" minnum="1" class="itxt"><a @click="getskuNum('add',1,item)" class="plus">+</a></li>
async getIsChecked(item, event) {try {let isChecked = event.target.checked ? '1' : '0'await this.$store.dispatch('getisChecked', {skuId: item.skuId,isChecked})this.getData()} catch (e) {// alert(e.message)//TODO handle the exception}console.log(item)}

总价

需要先过滤isCheck==1的数据,再从数组中遍历出对象的单价和数量相乘,再用reduce进行累加

totalPrice() {let res = this.getcartInfoList.filter(item => {return item.isChecked === 1}).map(item => {return item.skuNum * item.skuPrice}).reduce((pre, cur) => {return pre + cur})return res}

删除当前的商品

需要携带id,并且method是delete

一样的三连环

<li class="cart-list-con7"><a class="sindelet" @click="deleteShopcart(item.skuId)">删除</a><br><a href="#none">移到收藏</a></li>
async deleteShopcart(skuId) {// console.log(skuId)try {await this.$store.dispatch('deleteshopcart', skuId)this.getData()} catch (e) {alert(e.message)//TODO handle the exception}},
// 购物车删除
export function reqdeleteShop(skuId){return request({url:`/cart/deleteCart/${skuId}`,method:'delete'})
}
// 删除单个的商品async deleteshopcart({commit},skuId){const res = await reqdeleteShop(skuId)// console.log(res)if(res.code == 200){return 'ok'}else{return Promise.reject(new Error('false'))}},

控制当前商品的是否选中

请求地址:/cart/checkCart/{skuID}/{isChecked},method:get

还是三连环,不过需要获取当前checkbox的选中状态,所以在方法里面还需要传参数$event,在方法中event.target.checked

<li class="cart-list-con1"><input type="checkbox" name="chk_list" :checked="item.isChecked==1"@change="getIsChecked(item,$event)"></li>
async getIsChecked(item, event) {try {let isChecked = event.target.checked ? '1' : '0'await this.$store.dispatch('getisChecked', {skuId: item.skuId,isChecked})this.getData()} catch (e) {alert(e.message)//TODO handle the exception}console.log(item)},

删除选中的商品

过滤ischeck==1的商品再遍历商品,再派发dispatch,最后重新获取商品数据

<a @click="deleteAllshop">删除选中的商品</a>
async deleteAllshop() {try {await this.$store.dispatch('deleteAllshops')this.getData()} catch (e) {alert(e.message)}},
// 删除全部勾选的商品deleteAllshops({getters,dispatch}){// 获取购物车中全部的产品// let promiseall = []// getters.getshopcartList.cartInfoList.forEach(item=>{//    let promise = item.isChecked==1?dispatch('deleteshopcart',item.skuId):''//   // 将每一次返回的Promise添加到数组中//   promiseall.push(promise)// })// return Promise.all(promiseall)let promiseall = getters.getshopcartList.cartInfoList.filter(item=>{return item.isChecked === 1}).map(item=>{return dispatch('deleteshopcart',item.skuId)})// // 只要全部的p1|p2....都成功,返回的就是成功// // 如果有一个失败,返回就是失败return Promise.all(promiseall)},

全选

因为之前写过单选的checked的actions,所以当写全选这个按钮的时候,把所有的checked都遍历一遍,然后再调用dispath之前单选的按钮

// 全选checkbox状态allCheck({getters,dispatch},isChecked){// console.log(getters.getshopcartList)// if(e == true){let promiseall = getters.getshopcartList.cartInfoList.map(item =>{return dispatch('getisChecked',{skuId:item.skuId,isChecked})})return Promise.all(promiseall)// }// else{//  getters.getshopcartList.cartInfoList.map(item =>{//         item.checked = false//         return item.isChecked = 0//    })// }}

注册和注册验证

手机号,验证码,密码,确认密码,勾选协议

注册需要获取验证码,则需要使用api,文件中有这个api则使用,先获取接口/user/passport/sendCode/{phone},这里的接口带参数,双向绑定数据,v-model="phone"

把用户写入的phone传入到data中,再从事件中dispatch携带数据到actions,最后完成三连环,如果真的要把验证码发到用户手机上,需要钱,所以我们把发的验证码直接传到验证码的input上,则还要把state.user.code交给code,我们这里注册的规则用element-ui来验证,安装element,在

main中引入,新建一个plugins目录存放element使用的东西,注册的那几个input和checkbox合成表单,使用el-form和el-form-item,

<div class="elform"><el-form :model="ruleForm" :rules="rules" label-width='120px' ref='formRef'><el-form-item label='手机号:' prop='phone'><el-input type="text" v-model="ruleForm.phone" size="mini"></el-input></el-form-item><el-form-item label='验证码:' prop='code'><el-input type="text" v-model="ruleForm.code"><el-button slot="append" type="primary" @click="getCode">获取验证码</el-button></el-input></el-form-item><el-form-item label='密码:' prop='password'><el-input type="password" v-model="ruleForm.password" autocomplete="off" show-password></el-input></el-form-item><el-form-item label='确认密码:' prop='password1'><el-input type="text" v-model="ruleForm.password1" show-password></el-input></el-form-item><el-form-item prop='ischeck'><el-checkbox name="m1" v-model="ruleForm.ischeck" @change="changebox" :checked="true"></el-checkbox><span>同意协议并注册《尚品汇用户协议》</span></el-form-item><el-form-item><el-button @click="userRegister" type="primary">完成注册</el-button></el-form-item></el-form></div>
data() {// 手机号的校验规则var validatePhone = (rule, value, callback) => {const RegPhone = /^[1][3,4,5,7,8,9][0-9]{9}$/if (RegPhone.test(value)) {return callback()}callback(new Error('请输入正确的手机号'))}// 确认密码的验证规则var validatePass1 = (rule, value, callback) => {if (value === '') {callback(new Error('请再次输入密码'));} else if (value !== this.ruleForm.password) {callback(new Error('两次输入密码不一致!'));} else {callback();}}return {labelPosition: 'right',ruleForm: {phone: '',code: '',password: '',password1: '',ischeck: ''},rules: {phone: [{required: true,message: '请输入手机号',trigger: 'blur'},{validator: validatePhone,trigger: 'blur'}],code: [{required: true,message: '请输入验证码',trigger: 'blur'}],password: [{required: true,message: '请输入密码',trigger: 'blur'},{min: 6,max: 10,message: '长度在 6 到 10 个字符',trigger: 'blur'}],password1: [{required: true,message: '请确认密码',trigger: 'blur'},{validator: validatePass1,trigger: 'blur'}],ischeck: [{required: true,message: '请勾选同意协议',trigger: 'change'}]}}},
methods: {async getCode() {try {let res = await this.$store.dispatch('getcode', this.ruleForm.phone)this.ruleForm.code = this.$store.state.user.codenum// console.log(res)} catch (e) {alert(e.message)}},changebox(val) {this.ruleForm.ischeck = val},async userRegister() {try {this.$refs.formRef.validate(async valid => {if (!valid) return falselet aw = await this.$store.dispatch('getUserRegister', {phone: this.ruleForm.phone,code: this.ruleForm.code,password: this.ruleForm.password})this.$router.push('/login')})} catch (e) {alert(e.message)//TODO handle the exception}}}

登录

登录还是需要双向绑定phone和password然后传入api,post请求,传入两个参数,用括号包起来,这个请求的result.data会返回一个token值,我们把这个值本地存储起来,也就是下一步的内容

给登录网页的用户一个token值

本地存储token

先setItem存储token的值

// 持久化存储tokenlocalStorage.setItem('Token',res.data.token)

然后再getItem获取值

// 获取tokentoken:localStorage.getItem('Token'),

获取的token需要传给请求拦截器把token带给服务器

这段代码放在requet.js的请求头里面

//需要携带token带给服务器if(store.state.user.token){config.headers.token = store.state.user.token;}

退出登录

退出登录需要引入api,并且引入api之后,把用户的登录时生成的{}清空,token值清空,并且需要把本地存储的数据清空

//退出登录async userLogout({commit}) {//只是向服务器发起一次请求,通知服务器清除tokenlet result = await reqLogout();//action里面不能操作state,提交mutation修改stateif(result.code==200){commit("CLEAR");return 'ok';}else{return Promise.reject(new Error('faile'));}},
CLEAR(state,codenum,token,userinfo){state.codenum = ''// 清空tokenstate.token = localStorage.removeItem('Token')state.userinfo = {}}

qrcode(生成支付二维码)

用户在支付的时候,会生成一个二维码供用户扫码支付,我们会用到一个在线生成二维码的一个npm自带一个东西:qrcode

首先安装npm i qrcode --save

然后使用他

import QRCode from 'qrcode'
// 生成二维码
let orderurl = await QRCode.toDataURL(this.OrderInfo.codeUrl)

并且需要一个element-ui的弹框的api

async open() {// 生成二维码let orderurl = await QRCode.toDataURL(this.OrderInfo.codeUrl)this.$alert(`<img src=${orderurl} />`, '微信支付', {dangerouslyUseHTMLString: true,center: true,showCancelButton: true,showClose:false,cancelButtonText: '支付遇见的问题',confirmButtonText: '支付成功',beforeClose: (action, instance, done) => {if (action === 'cancel') {alert('请联系管理员')// 清除定时器clearInterval(this.timer)this.timer = null// 关闭弹出框done()}else{if(this.code == 205){clearInterval(this.timer)this.timer = null done()this.$router.push('/paysuccess')}}//     // console.log(action)}});

支付成功

当支付的二维码显示出来后,我们需要获取用户此时支付状态,通过定时器来获取此时是否支付完毕,当code为205时(这里应该是200,但200要花钱),用定时器包裹着api,并且定时每1秒,当code为205时,需要清除定时器,并且让timer为null,关闭弹框,最后跳转路由

// 支付成功,路由跳转  支付失败,提示信息if (!this.timer) {this.timer = setInterval(async () => {let res = await this.$api.reqOrderState(this.OrderInfo.orderId)if (res.code == 205) {clearInterval(this.timer)this.timer = null// 保存支付成功返回的codethis.code = 205// 关闭弹出框this.$msgbox.close()// 跳转路由this.$router.push('/paysuccess')// console.log(res,'支付成功')}}, 1000)// clearInterval(this.timer)}

路由守卫

全局守卫写在router.js中

router对象调用

.beforeEach((进入到哪一个路由,从哪一个路由离开,对应的函数)=>{})

// 全局守卫:前置守卫(在路由跳转之间进行判断0)
router.beforeEach((to,from,next)=>{// console.log(next)// next()let token = store.state.user.tokenif(token){// 用户已经登陆了还想去login【不能去,停留在首页】if(to.path=='/login'||to.path=='/register'){next('/')}else{next()}}else{let toPath = to.path// 用户没有登录还想跳转支付页面if(to.matched.some(item =>item.meta.isAuther)){next('/login?redirect='+toPath)}else{next()}}
})

else中没有登录点击pay的时候跳转到login,并且在login登录后跳转到pay用to.path连接,用拼接字符串的形式

独享守卫

写在routes的route中

beforeEnter:只能由shopcart进入到trade,否则next(false),只能由trade进入pay,否则next(false)

{path:'/trade',component:trade,name:'trade',meta:{show:false},beforeEnter:(to,from,next)=>{if(from.path=='/shopcart'){next()}else{next(false)}}},{path:'/pay',component:pay,name:'pay',meta:{show:false,isAuther:true},beforeEnter:(to,from,next)=>{if(from.path=='/trade'){next()}else{next(false)}}}

组件守卫

//1.组件进入之前的守卫
beforeRouteEnter(to,from,next){//和全局使用一样}    //生命周期还没开始,所以这个函数没有this//2.组件更新守卫
beforeRouteUpdate(to,from,next){//和全局使用一样}  //  "/:id"动态路由发生变化,页面没有重新加载,触发更新守卫//3.组件离开守卫
beforeRouteLeave(to,from,next){//和全局使用一样}    //在离开当前路由的时候触发,有this

组件内守卫(查看paysuccess

 export default {name: 'paysuccess',beforeRouteEnter(to,from,next) {if(from.path=='/pay'){next()}else{next(false)}}}

vue-lazyload(图片懒加载)

安装npm i vue-lazyload --save

在main.js全局引入

// 引入懒加载
import VueLazyload from 'vue-lazyload'
// 引入懒加载图片
import lazyimg from '@/assets/lazy.jpg'
Vue.use(VueLazyload,{// 懒加载默认图片loading: lazyimg,
})

打包

npm run build

尚品汇小结(-前端完成)相关推荐

  1. Vue前端项目【尚品汇】

    Vue前端项目[尚品汇] 1. 说明 2. 对项目创建 3.结构 4. 项目运行起来时,浏览器自动打开 5.关闭ESLint校验功能 5.路由分析 6.路由元信息 7. 路由传参 7.1 路由的跳转方 ...

  2. 前端 | ( 九)尚品汇实操练习 | 尚硅谷前端html+css零基础教程2023最新

    学习来源:尚硅谷前端html+css零基础教程,2023最新前端开发html5+css3视频 系列笔记: [HTML4](一)前端简介 [HTML4](二)各种各样的常用标签 [HTML4](三)表单 ...

  3. 尚硅谷VUE项目实战,前端项目-尚品汇

    001-尚硅谷-尚品汇-教程简介_哔哩哔哩_bilibili 需要的知识点   搭建vue-router pages文件夹放置路由页面 router文件夹配置路由 回到入口文件注册(main.js) ...

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

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

  5. 尚硅谷 VUE 尚品汇项目实战问题解决方式整理(Vue3 版)

    教学视频:https://www.bilibili.com/video/BV1Vf4y1T7bw 不回要资料的评论,资料在视频底下评论有些仓库里面有. 试图自行解决问题也是程序员必备技能之一,多做尝试 ...

  6. vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

    文章目录 29.加入购物车操作(难点) 29.1加入购物车按钮 29.2addCartSuce 29.3购物车 29.3.1 向服务器发送ajax请求,获取购物车数据 29.3.2UUID临时游客身份 ...

  7. 尚品汇_第3章_平台属性管理

    尚品汇_第3章__平台属性管理 文章目录 尚品汇_第3章__平台属性管理 一.商品的基本知识 1.1 基本信息-分类 1.2 基本信息-平台属性 1.3 基本信息-销售属性与销售属性值 1.4 基本信 ...

  8. vue实战项目-电商商城前台-(学习尚硅谷的)尚品汇

    文章目录 最好使用视频上的账号密码,13700000000 密:111111 最新服务端接口地址:http://gmall-h5-api.atguigu.cn 脚手架使用 1.创建项目 2.脚手架默认 ...

  9. ① 尚品汇的后台管理系统【尚硅谷】【Vue】

    后台管理系统项目简介 什么是后台管理系统项目? 在前端领域当中,开发后台管理系统项目,并非是Java,PHP等后台语言项目 在前面课程当中,我们已经开发了一个项目[尚品汇电商平台项目],这个项目主要针 ...

最新文章

  1. python路径拼接os.path.join()函数的用法
  2. ubuntu 用命令行设置chrome的proxy
  3. RPC框架——简单高效hessian的使用方式
  4. 英雄联盟手游:大神开发提莫打野,伤害爆表,玩家纷纷效仿
  5. 收件服务器信息,收件服务器配置信息
  6. 关于AI Architecture未来的一些思考
  7. 新冠病例继续攀升 苹果关闭纽约市所有实体店
  8. ubuntu安装python环境_AirSim 无人驾驶教程(1)Airsim 在Ubuntu环境下的安装
  9. 阳黎盛:4.11美联储预计加息,脱欧被顺延!
  10. 3D Computer Grapihcs Using OpenGL - 18 相机移动
  11. dx 汇编dec_汇编语言算术指令
  12. 【AD10】Altium Designer 10导入元件库图文教程
  13. 简要html漂浮广告代码,JS漂浮广告代码
  14. 刘晓燕,考研核心词汇1500,1-20讲【前十讲】【谐音记忆】【没人比我详细】【超级原创】
  15. 【教程】简单5步教你手机制作寸照、证件照、照片回执
  16. 乐筑携手大通,共筑全球绳网产业互联网领导者平台
  17. java面试的笔试题
  18. matlab fgetc,fgetc函数的作用是什么
  19. MySQL复制表-CREATE SELECT
  20. 奥利地公司利用Windows 和 Adobe 0day 攻击欧洲和中美洲实体

热门文章

  1. TreeNode(string,int32,int32)构造函数详解
  2. 【云原生 | 从零开始学istio】五、istio灰度发布以及核心资源
  3. C# 终于会实时获得麦克风的响度了
  4. python饼图显示百分比_解决echarts饼图显示百分比,和显示内容字体及大小
  5. MSP430 与 ARM Cortex系列在电池供电应用上的比较
  6. DHL测试新包裹站,只需要一个App
  7. Java中3大线程安全的map
  8. ISP_反马赛克_色彩差值_通过RGB生成RAW类图
  9. NOJ ACM-ICPC Graveyard
  10. windows自带卸载工具(彻底卸载)