import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
setInterceptor(instance) {
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
return res.data.data
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
}
export default new Http()
import http from '@/utils/http.js'
const API_LIST = {
queryIndexInfos: '/index-infos' // 首页的获取数据接口,都在这里
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
{{ title || $route.meta.title }}
{{ isLogin ? '还没账号,请点此注册' : '已有账号,请点此登录' }}
确认提交
{{ captchaImgText }}
pnpm i blueimp-md5
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register'
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
核心操作:
src/utils/http.js
import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
setInterceptor(instance) {
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
// 对返回值的状态码是200的情况统一处理
return res.data.data
}
if (res.data.resultCode === 500) {
return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
}
export default new Http()
src/api/index.js
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
userLogin: '/user/login',
userRegister: '/user/register'
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
src/views/Login.vue
{{ isLogin ? '还没账号,请点此注册' : '已有账号,请点此登录' }}
确认提交
{{ captchaImgText }}
代码示例
src/utils/http.js
import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
constructor() {
// 根据环境变量设置请求的路径
this.baseURL = import.meta.env.DEV ? 'http://backend-api-01.newbee.ltd/api/v1' : '/'
this.timeout = 5000
}
setInterceptor(instance) {
instance.interceptors.request.use(
(config) => {
// 携带token来做处理
return config
},
(err) => {
return Promise.reject(err)
}
)
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
// 对返回值的状态码是200的情况统一处理
return res.data.data
}
if (res.data.resultCode === 500) {
return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
request(options) {
// 请求会实现拦截器
const instance = axios.create() // 1.每次请求要创建一个新的实例
this.setInterceptor(instance) // 2.设置拦截器
// 发送请求参数
return instance({
...options,
baseURL: this.baseURL,
timeout: this.timeout
})
}
get(url, data) {
return this.request({
method: 'get',
url,
params: data
})
}
post(url, data) {
return this.request({
method: 'post',
url,
data
})
}
}
export default new Http()
src/api/index.js
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register'
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
src/components/Captcha.vue
src/views/Login.vue
{{ isLogin ? '还没账号,请点此注册' : '已有账号,请点此登录' }}
确认提交
{{ captchaImgText }}
代码示例
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: Home,
meta: { title: '首页' }
},
{
path: '/category',
meta: { title: '分类' },
name: 'category',
component: () => import('../views/Category.vue')
},
{
path: '/cart',
name: 'cart',
component: () => import('../views/Cart.vue'),
meta: {
needLogin: true // 需要登录才能访问的 我们需要配置这个属性
}
},
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
}
]
})
router.beforeEach(async (to, from) => {
let token = localStorage.getItem('token')
if (token) {
// 如果有token 说明登录成功,但是如果你访问的还是登录
if (to.name === 'login') {
return { path: '/' }
}
} else {
// 没有登录,跳转到登录页面
// /a/b -> ['/a','/a/b']
if (to.matched.some((item) => item.meta.needLogin)) {
// 此路由需要登录但是没有登录, 应该跳转到登录页面
return {
path: '/login',
query: {
redirect: to.path, // 跳转到登录页面,并且告诉登录页面稍后回调回来
...to.query // 当前页面的其他参数也添加进去
}
}
}
}
})
export default router
src/views/Login.vue
{{ isLogin ? '还没账号,请点此注册' : '已有账号,请点此登录' }}
确认提交
{{ captchaImgText }}
核心代码
src/router/index.js
const router = createRouter({
routes: [
{
path: '/cart',
name: 'cart',
component: () => import('../views/Cart.vue'),
meta: {
needLogin: true // 需要登录才能访问的 我们需要配置这个属性
}
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
}
]
})
router.beforeEach(async (to, from) => {
let token = localStorage.getItem('token')
if (token) {
// 如果有token 说明登录成功,但是如果你访问的还是登录
if (to.name === 'login') {
return { path: '/' }
}
} else {
// 没有登录,跳转到登录页面
// /a/b -> ['/a','/a/b']
if (to.matched.some((item) => item.meta.needLogin)) {
// 此路由需要登录但是没有登录, 应该跳转到登录页面
return {
path: '/login',
query: {
redirect: to.path, // 跳转到登录页面,并且告诉登录页面稍后回调回来
...to.query // 当前页面的其他参数也添加进去
}
}
}
}
})
export default router
src/views/Login.vue
确认提交
核心代码:
src/api/index.js
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryCategories: '/categories' // 查询分类的路径
}
// 查询所有的分类
export function queryCategories() {
return http.get(API_LIST.queryCategories)
}
src/stores/category.js
import { queryCategories } from '@/api'
export const useCategoryStore = defineStore('category', () => {
const list = ref([]) // 默认所有分类的信息
async function getCategories() {
list.value = await queryCategories()
}
return { list, getCategories }
})
src/views/Category.vue
代码示例:
src/api/index.js
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register',
queryCategories: '/categories' // 查询分类的路径
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
// 查询所有的分类
export function queryCategories() {
return http.get(API_LIST.queryCategories)
}
src/stores/category.js
import { queryCategories } from '@/api'
export const useCategoryStore = defineStore('category', () => {
const list = ref([]) // 默认所有分类的信息
async function getCategories() {
list.value = await queryCategories()
}
return { list, getCategories }
})
src/views/Category.vue
{{ content.categoryName }}
{{ item.categoryName }}
import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
constructor() {
// 根据环境变量设置请求的路径
this.baseURL = import.meta.env.DEV ? 'http://backend-api-01.newbee.ltd/api/v1' : '/'
this.timeout = 5000
}
setInterceptor(instance) {
instance.interceptors.request.use(
(config) => {
// 携带token来做处理
let token = localStorage.getItem('token')
if (token) {
config.headers['token'] = token
}
return config
},
(err) => {
return Promise.reject(err)
}
)
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
// 对返回值的状态码是200的情况统一处理
return res.data.data
}
if (res.data.resultCode === 500) {
return Promise.reject(res.data)
}
if (res.data.resultCode === 416) {
localStorage.removeItem('token') // 416 可能是token错误,这个时候清除token,重新刷新
// 刷新后就在此路由的全局钩子,就会走没有token的逻辑
return window.location.reload()
// return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
request(options) {
// 请求会实现拦截器
const instance = axios.create() // 1.每次请求要创建一个新的实例
this.setInterceptor(instance) // 2.设置拦截器
// 发送请求参数
return instance({
...options,
baseURL: this.baseURL,
timeout: this.timeout
})
}
get(url, data) {
return this.request({
method: 'get',
url,
params: data
})
}
post(url, data) {
return this.request({
method: 'post',
url,
data
})
}
}
export default new Http()
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register',
queryCategories: '/categories', // 查询分类的路径
queryGoodsInfo: '/goods/detail'
}
export const queryGoodsInfo = (id) => {
return http.get(API_LIST.queryGoodsInfo + `/${id}`)
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
// 查询所有的分类
export function queryCategories() {
return http.get(API_LIST.queryCategories)
}
{{ title }}
{{ goods.goodsIntro }}
{{ addPrefix(goods.sellingPrice) }}
class Http {
setInterceptor(instance) {
instance.interceptors.request.use(
(config) => {
// 携带token来做处理
let token = localStorage.getItem('token')
if (token) {
config.headers['token'] = token
}
return config
},
(err) => {
return Promise.reject(err)
}
)
}
}
import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
constructor() {
// 根据环境变量设置请求的路径
this.baseURL = import.meta.env.DEV ? 'http://backend-api-01.newbee.ltd/api/v1' : '/'
this.timeout = 5000
}
setInterceptor(instance) {
instance.interceptors.request.use(
(config) => {
// 携带token来做处理
let token = localStorage.getItem('token')
if (token) {
config.headers['token'] = token
}
return config
},
(err) => {
return Promise.reject(err)
}
)
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
// 对返回值的状态码是200的情况统一处理
return res.data.data
}
if (res.data.resultCode === 500) {
return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
request(options) {
// 请求会实现拦截器
const instance = axios.create() // 1.每次请求要创建一个新的实例
this.setInterceptor(instance) // 2.设置拦截器
// 发送请求参数
return instance({
...options,
baseURL: this.baseURL,
timeout: this.timeout
})
}
get(url, data) {
return this.request({
method: 'get',
url,
params: data
})
}
post(url, data) {
return this.request({
method: 'post',
url,
data
})
}
}
export default new Http()
import axios from 'axios'
// 请求的时候可以做什么事? 1)拦截 携带token, 对响应状态码处理, 2)增加loading (增添一个队列) 3)接口可以保存取消的操作
class Http {
constructor() {
// 根据环境变量设置请求的路径
this.baseURL = import.meta.env.DEV ? 'http://backend-api-01.newbee.ltd/api/v1' : '/'
this.timeout = 5000
}
setInterceptor(instance) {
instance.interceptors.request.use(
(config) => {
// 携带token来做处理
let token = localStorage.getItem('token')
if (token) {
config.headers['token'] = token
}
return config
},
(err) => {
return Promise.reject(err)
}
)
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode == 200) {
// 对返回值的状态码是200的情况统一处理
return res.data.data
}
if (res.data.resultCode === 500) {
return Promise.reject(res.data)
}
if (res.data.resultCode === 416) {
localStorage.removeItem('token') // 416 可能是token错误,这个时候清除token,重新刷新
// 刷新后就在此路由的全局钩子,就会走没有token的逻辑
return window.location.reload()
// return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
request(options) {
// 请求会实现拦截器
const instance = axios.create() // 1.每次请求要创建一个新的实例
this.setInterceptor(instance) // 2.设置拦截器
// 发送请求参数
return instance({
...options,
baseURL: this.baseURL,
timeout: this.timeout
})
}
get(url, data) {
return this.request({
method: 'get',
url,
params: data
})
}
post(url, data) {
return this.request({
method: 'post',
url,
data
})
}
}
export default new Http()
class Http {
setInterceptor(instance) {
instance.interceptors.response.use(
(res) => {
if (res.data.resultCode === 416) {
localStorage.removeItem('token') // 416 可能是token错误,这个时候清除token,重新刷新
// 刷新后就在此路由的全局钩子,就会走没有token的逻辑
return window.location.reload()
// return Promise.reject(res.data)
}
return res.data // {resultCode:200,data:{}}
},
(err) => {
return Promise.reject(err)
}
)
}
}
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: Home,
meta: { title: '首页' }
},
{
path: '/category',
meta: { title: '分类' },
name: 'category',
component: () => import('../views/Category.vue')
},
{
path: '/cart',
name: 'cart',
component: () => import('../views/Cart.vue'),
meta: {
needLogin: true // 需要登录才能访问的 我们需要配置这个属性
}
},
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
},
{
path: '/detail/:id',
name: 'detail',
meta: {
needLogin: true
},
component: () => import('../views/Detail.vue')
}
]
})
router.beforeEach(async (to, from) => {
let token = localStorage.getItem('token')
if (token) {
// 如果有token 说明登录成功,但是如果你访问的还是登录
if (to.name === 'login') {
return { path: '/' }
}
} else {
// 没有登录,跳转到登录页面
// /a/b -> ['/a','/a/b']
if (to.matched.some((item) => item.meta.needLogin)) {
// 此路由需要登录但是没有登录, 应该跳转到登录页面
return {
path: '/login',
query: {
redirect: to.path, // 跳转到登录页面,并且告诉登录页面稍后回调回来
...to.query // 当前页面的其他参数也添加进去
}
}
}
}
})
export default router
// 获取购物车列表
export const queryShopCart = () => http.get('/shop-cart')
// 修改购买数量
export const setCartCount = (cartItemId, goodsCount) => {
return http.request(
{
url: '/shop-cart',
method: 'PUT'
},
{
cartItemId,
goodsCount
}
)
}
// 删除某条购物车数据
export const removeCart = (cartItemId) => {
return http.request({
url: `/shop-cart/${cartItemId}`,
method: 'DELETE'
})
}
// 新增购物车数据
export const addNewCart = (goodsId, goodsCount = 1) => {
return http.post('/shop-cart', {
goodsId,
goodsCount
})
}
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
}
return { list, getShopCartList, setShopCartItem, removeShopCartItem, addShopCartItem }
})
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register',
queryCategories: '/categories', // 查询分类的路径
queryGoodsInfo: '/goods/detail'
}
// 获取购物车列表
export const queryShopCart = () => http.get('/shop-cart')
// 修改购买数量
export const setCartCount = (cartItemId, goodsCount) => {
return http.request(
{
url: '/shop-cart',
method: 'PUT'
},
{
cartItemId,
goodsCount
}
)
}
// 删除某条购物车数据
export const removeCart = (cartItemId) => {
return http.request({
url: `/shop-cart/${cartItemId}`,
method: 'DELETE'
})
}
// 新增购物车数据
export const addNewCart = (goodsId, goodsCount = 1) => {
return http.post('/shop-cart', {
goodsId,
goodsCount
})
}
export const queryGoodsInfo = (id) => {
return http.get(API_LIST.queryGoodsInfo + `/${id}`)
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
// 查询所有的分类
export function queryCategories() {
return http.get(API_LIST.queryCategories)
}
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
const hasCartStore = ref(false)
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
hasCartStore.value = true
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
}
return {
list,
getShopCartList,
setShopCartItem,
removeShopCartItem,
addShopCartItem,
hasCartStore
}
})
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import { useCartStore } from '@/stores/cart.js'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: Home,
meta: { title: '首页' }
},
{
path: '/category',
meta: { title: '分类' },
name: 'category',
component: () => import('../views/Category.vue')
},
{
path: '/cart',
name: 'cart',
component: () => import('../views/Cart.vue'),
meta: {
needLogin: true // 需要登录才能访问的 我们需要配置这个属性
}
},
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
},
{
path: '/detail/:id',
name: 'detail',
meta: {
needLogin: true
},
component: () => import('../views/Detail.vue')
}
]
})
// 登陆态校验。
router.beforeEach(async (to, from) => {
let token = localStorage.getItem('token')
if (token) {
// 如果有token 说明登录成功,但是如果你访问的还是登录
if (to.name === 'login') {
return { path: '/' }
}
} else {
// 没有登录,跳转到登录页面
// /a/b -> ['/a','/a/b']
if (to.matched.some((item) => item.meta.needLogin)) {
// 此路由需要登录但是没有登录, 应该跳转到登录页面
return {
path: '/login',
query: {
redirect: to.path, // 跳转到登录页面,并且告诉登录页面稍后回调回来
...to.query // 当前页面的其他参数也添加进去
}
}
}
}
})
//
router.beforeEach(() => {
let token = localStorage.getItem('token')
if (token) {
const store = useCartStore()
if (!store.hasCartStore) {
// 如果当前没有获取过购物车信息
store.getShopCartList()
}
}
})
export default router
import http from '@/utils/http.js'
import md5 from 'blueimp-md5'
const API_LIST = {
queryIndexInfos: '/index-infos', // 首页的获取数据接口,都在这里
userLogin: '/user/login',
userRegister: '/user/register',
queryCategories: '/categories', // 查询分类的路径
queryGoodsInfo: '/goods/detail'
}
// 获取购物车列表
export const queryShopCart = () => http.get('/shop-cart')
// 修改购买数量
export const setCartCount = (cartItemId, goodsCount) => {
return http.request({
url: '/shop-cart',
method: 'PUT',
data: {
cartItemId,
goodsCount
}
})
}
// 删除某条购物车数据
export const removeCart = (cartItemId) => {
return http.request({
url: `/shop-cart/${cartItemId}`,
method: 'DELETE'
})
}
// 新增购物车数据
export const addNewCart = (goodsId, goodsCount = 1) => {
return http.post('/shop-cart', {
goodsId,
goodsCount
})
}
export const queryGoodsInfo = (id) => {
return http.get(API_LIST.queryGoodsInfo + `/${id}`)
}
// 首页数据的获取,直接通过 api 这个文件来操作
export function queryIndexInfos() {
return http.get(API_LIST.queryIndexInfos)
}
// md5特点? 不是加密算法,摘要算法 1)内容不同摘要的结果不同 2) 如果内容发生一点变化就会发生翻天覆地的变化 , 雪崩效应
// 3) 生成长度一致 4)相同的内容生成的结果一直 5) 不可逆
export const userLogin = (loginName, password) => {
password = md5(password)
return http.post(API_LIST.userLogin, {
loginName,
passwordMd5: password
})
}
// 用户注册
export const userRegister = (loginName, password) => {
return http.post(API_LIST.userRegister, {
loginName,
password
})
}
// 查询所有的分类
export function queryCategories() {
return http.get(API_LIST.queryCategories)
}
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
const hasCartStore = ref(false)
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
hasCartStore.value = true
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新,如果是修改也可以不发请求 通过id 获取到这一项,更改数量即可
list.value.find((item) => item.cartItemId == id).goodsCount = count
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
// 正常操作的情况下 应该是添加成功后,返回添加后的值
getShopCartList()
}
return {
hasCartStore,
list,
getShopCartList,
setShopCartItem,
removeShopCartItem,
addShopCartItem
}
})
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
const hasCartStore = ref(false)
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
hasCartStore.value = true
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新,如果是修改也可以不发请求 通过id 获取到这一项,更改数量即可
list.value.find((item) => item.cartItemId == id).goodsCount = count
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
// 正常操作的情况下 应该是添加成功后,返回添加后的值
getShopCartList()
}
return {
hasCartStore,
list,
getShopCartList,
setShopCartItem,
removeShopCartItem,
addShopCartItem
}
})
全选
{{ info.goodsName }}
商品介绍
{{ info.sellingPrice }}
{{ info.goodsName }}
{{ info.sellingPrice }}
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
const hasCartStore = ref(false)
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
hasCartStore.value = true
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新,如果是修改也可以不发请求 通过id 获取到这一项,更改数量即可
list.value.find((item) => item.cartItemId == id).goodsCount = count
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
// 正常操作的情况下 应该是添加成功后,返回添加后的值
getShopCartList()
}
const badge = computed(() => {
// 暂时先计算出 我们当前选中的详情页的数量
const current = list.value.reduce((memo, current) => ((memo += current.goodsCount), memo), 0)
return current
})
return {
badge,
hasCartStore,
list,
getShopCartList,
setShopCartItem,
removeShopCartItem,
addShopCartItem
}
})
全选
首页
分类
购物车
我的
{{ info.goodsName }}
商品介绍
{{ info.sellingPrice }}
{{ info.goodsName }}
{{ info.sellingPrice }}
全选
// 1.获取购物车列表queryShopCart
// 2.修改数量 哪个商品的数量是多少 setCartCount
// 3.删除购物车的某个商品 removeCart
// 4.新增只传递新增的id即可addNewCart
// @ts-ignore
import { queryShopCart, setCartCount, removeCart, addNewCart } from '@/api'
export const useCartStore = defineStore('cart', () => {
const list = ref([])
const hasCartStore = ref(false)
// 在pinia中缓存数据
async function getShopCartList() {
list.value = await queryShopCart()
hasCartStore.value = true
}
async function setShopCartItem(id, count) {
await setCartCount(id, count)
// 将列表中的数据也要更新,如果是修改也可以不发请求 通过id 获取到这一项,更改数量即可
list.value.find((item) => item.cartItemId == id).goodsCount = count
}
async function removeShopCartItem(id) {
await removeCart(id)
// 将列表中的数据也要更新
list.value = list.value.filter((item) => item.cartItemId != id)
}
async function addShopCartItem(id) {
await addNewCart(id)
// 将列表中的数据也要更新
// 正常操作的情况下 应该是添加成功后,返回添加后的值
getShopCartList()
}
const badge = computed(() => {
// 暂时先计算出 我们当前选中的详情页的数量
const current = list.value.reduce((memo, current) => ((memo += current.goodsCount), memo), 0)
return current
})
const total = computed(() => {
return list.value.reduce((memo, current) => {
if (current.checked) {
// 选中就累加
memo += current.goodsCount * current.sellingPrice
}
return memo
}, 0)
})
const isCheckedAll = computed({
get() {
return list.value.every((item) => item.checked)
},
set(newVal) {
list.value.forEach((item) => (item.checked = newVal))
}
})
return {
total,
isCheckedAll,
badge,
hasCartStore,
list,
getShopCartList,
setShopCartItem,
removeShopCartItem,
addShopCartItem
}
})
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import { useCartStore } from '@/stores/cart'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: Home,
meta: { title: '首页' }
},
{
path: '/category',
meta: { title: '分类' },
name: 'category',
component: () => import('../views/Category.vue')
},
{
path: '/cart',
name: 'cart',
component: () => import('../views/Cart.vue'),
meta: {
needLogin: true // 需要登录才能访问的 我们需要配置这个属性
}
},
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
},
{
path: '/detail/:id',
name: 'detail',
meta: {
needLogin: true
},
component: () => import('../views/Detail.vue')
},
{
path: '/search',
name: 'search',
meta: {
needLogin: true
},
component: () => import('../views/Search.vue')
}
]
})
// 鉴权看是否登录过
router.beforeEach(async (to) => {
let token = localStorage.getItem('token')
if (token) {
// 如果有token 说明登录成功,但是如果你访问的还是登录
if (to.name === 'login') {
return { path: '/' }
}
} else {
// 没有登录,跳转到登录页面
// /a/b -> ['/a','/a/b']
if (to.matched.some((item) => item.meta.needLogin)) {
// 此路由需要登录但是没有登录, 应该跳转到登录页面
return {
path: '/login',
query: {
redirect: to.path, // 跳转到登录页面,并且告诉登录页面稍后回调回来
...to.query // 当前页面的其他参数也添加进去
}
}
}
}
})
// 如果登陆过查询是否已经获取购物车信息
// 获取购物车的信息存储到pinia中
router.beforeEach(() => {
let token = localStorage.getItem('token')
if (token) {
const store = useCartStore()
if (!store.hasCartStore) {
// 如果当前没有获取过购物车信息
store.getShopCartList()
}
}
})
export default router
import { queryCategories } from '@/api'
export const useCategoryStore = defineStore('category', () => {
const list = ref([]) // 默认所有分类的信息
async function getCategories() {
// 获取分类将获取的数据保存到list变量中
list.value = await queryCategories()
}
return { list, getCategories }
})
搜索
const stack = [
{
categoryId: 15,
categoryLevel: 1,
categoryName: '家电 数码 手机',
secondLevelCategoryVOS: [
{
categoryId: 17,
parentId: 15,
categoryLevel: 2,
categoryName: '家电',
thirdLevelCategoryVOS: [
{
categoryId: 20,
categoryLevel: 3,
categoryName: '生活电器'
},
{
categoryId: 110,
categoryLevel: 3,
categoryName: 'wer'
},
{
categoryId: 21,
categoryLevel: 3,
categoryName: '厨房电器'
},
{
categoryId: 22,
categoryLevel: 3,
categoryName: '扫地机器人'
},
{
categoryId: 31,
categoryLevel: 3,
categoryName: '空气净化器'
}
]
},
{
categoryId: 19,
parentId: 15,
categoryLevel: 2,
categoryName: '手机',
thirdLevelCategoryVOS: [
{
categoryId: 45,
categoryLevel: 3,
categoryName: '荣耀手机'
},
{
categoryId: 57,
categoryLevel: 3,
categoryName: 'vivo'
},
{
categoryId: 58,
categoryLevel: 3,
categoryName: '手机以旧换新'
}
]
}
]
},
{
categoryId: 16,
categoryLevel: 1,
categoryName: '女装 男装 穿搭',
secondLevelCategoryVOS: [
{
categoryId: 67,
parentId: 16,
categoryLevel: 2,
categoryName: '女装',
thirdLevelCategoryVOS: [
{
categoryId: 76,
categoryLevel: 3,
categoryName: '外套'
}
]
}
]
},
{
categoryId: 61,
categoryLevel: 1,
categoryName: '家具 家饰 家纺',
secondLevelCategoryVOS: [
{
categoryId: 70,
parentId: 61,
categoryLevel: 2,
categoryName: '家具',
thirdLevelCategoryVOS: [
{
categoryId: 77,
categoryLevel: 3,
categoryName: '沙发'
}
]
}
]
}
]
const result = []
console.log(`0. stack-->`, JSON.parse(JSON.stringify(stack)))
// 树的遍历, 层序遍历
let index = 0 // 指针
let current
// 递归会出现爆栈的问题,避免用递归
while ((current = stack[index++]) != null) {
if (current.categoryLevel == 1) {
stack.push(...current.secondLevelCategoryVOS)
console.log(`1. stack-->`, JSON.parse(JSON.stringify(stack)))
} else if (current.categoryLevel == 2) {
stack.push(...current.thirdLevelCategoryVOS)
console.log(`2. stack-->`, JSON.parse(JSON.stringify(stack)))
} else {
result.push({ text: current.categoryName, value: current.categoryId })
console.log(`3. stack-->`, JSON.parse(JSON.stringify(stack)))
}
}
console.log(`result-->`, result)