4. Project page — Product details page
Click through the home page and category page to enter the product details page
Obtain product details
GoodsListItem.vue >>
<template> <! -- Product list item --> <! --1-1Click on the route redirect with ID: @click="itemClick(product.id)" -->
<div class="good-item" @click="itemClick">
<img v-lazy="product.cover_url" alt="">
<div class="goods-info">
<p>{{product.title}}</p>
<span class="price"><small>RMB</small>{{product.price}}</span>
<span class="collect">{{product.collects_count}}</span>
</div>
</div>
</template>
<script >
import {useRouter} from 'vue-router'; // 1-2 Import router
export default {
name: "GoodsListItem".props: {// Receive the value passed by the parent component
product:Object.default(){
return{}}},setup(props) {
const router = useRouter() // 1-3 Declare the router
return {
itemClick: () = > {
router.push({path:'/detail'.query: {id:props.product.id}}) // This page has id, upload here; The page is cached
// console.log(props.product.id)}}}}</script>
<style scoped lang="scss">
.good-item{
width: 46%;
padding-bottom: 40px;
position: relative; // The inner layer is positioned relative to the outer layerimg{
width: 100%;
border-radius: 5%;
}
.goods-info{
font-size: 12px;
bottom: 5px;
overflow: hidden;
text-align: center;
Centered / * * /
position: absolute;
left: 0;
right: 0;
p{
overflow: hidden; // Hide the title out of scopetext-overflow: ellipsis; // Display text out of range...white-space: nowrap; // The text does not wrapmargin-bottom: 3px;
}
.price{
color: darkred;
margin-right: 20px;
}
.collect{
position: relative;
}
.collect::before{
center:' ';
position: absolute;
left: -15px;
width: 14px;
height: 14px;
top: -1;
background:url('~assets/images/collect.png')0 0 /14px 14px; }}}</style>
Copy the code
category.vue >>
<template>
<div>
<nav-bar>
<template v-slot:default>分类详情</template>
</nav-bar>
<div id="mainbox">
<!--6 不同排序方式-->
<div class="ordertab">
<van-tabs v-model="active" @click="tabClick">
<van-tab title="销量排序"></van-tab>
<van-tab title="价格排序"></van-tab>
<van-tab title="评价排序"></van-tab>
</van-tabs>
</div>
<!--5 折叠-->
<van-sidebar class="leftmenu" v-model="activeKey">
<van-collapse v-model="activeName" accordion><!--手风琴折叠-->
<van-collapse-item
v-for="item in categories" :key="item.id"
:title="item.name"
:name="item.name">
<!-- 子菜单-->
<van-sidebar-item
v-for="sub in item.children"
:title="sub.name"
:key="sub.id"
@click="getGoods(sub.id)"
/><!-- 4.变量categories.value中数据-->
</van-collapse-item>
</van-collapse>
</van-sidebar>
<!--商品列表-->
<div class="goodslist">
<div class="content">
<van-card
v-for="item in showGoods" :key="item.id"
@click="itemClick(item.id)"
:num="item.comments_count"
:tag="item.comments_count >=0 ? '流行':'标签'"
:price="item.price"
:desc="item.update_at"
:title="item.title"
:thumb="item.cover_url"
:lazy-load="true"
/>
</div>
</div>
</div>
<back-top @bTop="bTop" v-show="isShowBackTop"></back-top>
</div>
</template>
<script>
import NavBar from "../../components/common/navbar/NavBar";
import BackTop from "../../components/common/backtop/BackTop";// ️ 2-1 回到顶部
import {useRouter} from 'vue-router'
import {ref, reactive, onMounted, computed, watchEffect, nextTick} from 'vue';
import {getCategory,getCategoryGoods} from "../../network/category";
import BScroll from "better-scroll";
export default {
name: "Category",
setup(){
const router = useRouter()
let active = ref(1)
let activeKay = ref(0)
let activeName = ref(1)
//2.申明数组
let categories = ref([])
let isShowBackTop =ref(false)
//8当前的排序条件
let currentOrder = ref(['sales'])
//11 当前的分类id
let currentCid = ref(0)
//12数据模型
const goods = reactive({
sales:{page:1,list:[]},
price:{page:1,list:[]},
comments_count:{page:1,list:[]}
})
//13响应式的,更新数据
const showGoods = computed(()=>{
return goods[currentOrder.value].list
})
//13 初始化数据,将接口里的数据放到数据模型中去
const init =()=> {
getCategoryGoods('sales',currentCid.value).then(res=>{
goods.sales.list = res.goods.data
})
getCategoryGoods('price',currentCid.value).then(res=>{
goods.price.list = res.goods.data
})
getCategoryGoods('comments_count',currentCid.value).then(res=>{
goods.comments_count.list = res.goods.data
})
}
let bscroll = reactive({}); // 声明在外层 共用
onMounted(()=>{
//1 获取分类
getCategory().then(res=>{
// console.log(res)
// 3.获取res.categories的值,并赋给categories.value
categories.value = res.categories
// console.log(categories.value)
})
//只需一个,因为默认就是「sales」
getCategoryGoods('sales',currentCid.value).then(res=>{
goods.sales.list = res.goods.data
})
// 6 创建 BetterScroll 对象
bscroll = new BScroll(document.querySelector(".goodslist"), {
// 获取到最外层元素
probeType: 3, // 0,1,2,3, 3 只要在运行就触发 scroll 事件
click: true, // 是否允许点击
pullUpLoad: true, // 上拉加载更多,默认 false
});
//注册滚动事件
bscroll.on('scroll',(position)=>{
isShowBackTop.value = (-position.y)>30
})
// 10 上拉加载更多数据,触发 pullingUp
bscroll.on("pullingUp", () => {
console.log('上拉加载更多......')
const pages = goods[currentOrder.value].page +1
getCategoryGoods(currentOrder.value ,currentCid.value).then(res=>{
goods[currentOrder.value].list.push(...res.goods.data)
goods[currentOrder.value].page += 1
})
// 完成上拉,等数据请求完成,要将新数据展示出来
bscroll.finishPullUp();
//延迟效果
nextTick(() => {
// 当 DOM 渲染完了执行方法
// 重新计算高度
bscroll && bscroll.refresh();
});
// 刷新 重新计算高度
bscroll.refresh();
console.log('centerHeight:' + document.querySelector('.content').clientHeight)
console.log('当前类型:' + currentType.value + ',当前页:' + page)
});
});
//7 排序选项卡
const tabClick = (index)=>{
let orders = ['sales','price','comment_count']
//9
currentOrder.value = orders[index]
//14 更新,重新排序
getCategoryGoods(currentOrder.value ,currentCid.value).then(res=>{
goods[currentOrder.value].list = res.goods.data
//延迟效果
nextTick(() => {
// 当 DOM 渲染完了执行方法
// 重新计算高度
bscroll && bscroll.refresh();
});
})
console.log('当前分类id'+ currentCid.value)
console.log('排序的序号'+currentOrder.value)
}
//10 通过分类得到商品
const getGoods = (cid) =>{
currentCid.value = cid
init()//重新赋值
console.log('当前分类Id'+currentCid.value)
console.log('排序的序号'+ currentCid.value)
}
// 监听 任何一个变量有变化就会被触发
watchEffect(() => {
nextTick(() => {
// 当 DOM 渲染完了执行方法
// 重新计算高度
bscroll && bscroll.refresh();
});
});
const bTop =()=>{
bscroll.scrollTo(0,0,300)
}
return{
activeKay,
categories,
activeName,
active,
tabClick,
getGoods,
currentCid,
goods,
showGoods,
bscroll,
isShowBackTop,
bTop,
itemClick:(id)=>{
// console.log(id)
router.push({path:'/detail',query:{id}})
}
}
},
components: {
NavBar,
BackTop
}
}
</script>
<style scoped lang="scss">
#mainbox{
margin-top: 45px;
display: flex;
.ordertab{
height: 50px;
flex: 1;
float: right;
z-index: 9;
position: fixed;
top: 45px;
right: 0;
left: 130px;
}
.leftmenu{
width: 130px;
position: fixed;
top: 95px;
left: 0;
width: 130px;
}
.goodslist{
flex: 1;
position: absolute;
top: 100px;
left: 130px;
right: 0;
height: 100vh; /* 占领整个可用大小*/
padding: 10px;
text-align: left !important;
/*.content{*/
/* !*background-color: darkred;*!*/
/* padding-top: 10px;*/
/*}*/
}
}
.van-card__thumb{
width: 68px !important;
}
</style>
Copy the code
Detail.vue>>
<template>
<div>
<nav-bar>
<template v-slot:default>{{id}}</template>
</nav-bar>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {useRoute} from 'vue-router'
import {ref} from 'vue'
export default {
name: "Detail".components: {
NavBar
},
setup(){
const route = useRoute()
let id = ref(0)
id.value = route.query.id
return{
id
}
}
}
</script>
<style scoped>
</style>
Copy the code
detail.js >>
import {request} from "./request";
export function getDetail(id) {
return request({
url:'/api/goods/'+id,
})
}
Copy the code
detail.vue>>
<template>
<div>
<nav-bar>
<template v-slot:default>{{id}}</template>
</nav-bar>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {useRoute} from 'vue-router'
import {ref,reactive,onMounted,toRefs} from 'vue'
import {getDetail} from ".. /.. /network/detail";
export default {
name: "Detail".components: {
NavBar
},
setup(){
const route = useRoute()
let id = ref(0)
let book = reactive({
detail: {},like_goods: []// Similar books
})
//1 Mount the route
onMounted(() = >{
id.value = route.query.id
// 2 Add method, getDetail(), can receive id
getDetail(id.value).then(res= >{
// console.log(res)
book.detail = res.goods
book.like_goods = res.like_goods
})
})
return{ id, ... toRefs(book)/ / deconstruction}}}</script>
<style scoped>
</style>
Copy the code
2 Render product data to the template
The Image is introduced into
The enhanced IMG tag provides multiple image filling modes, and supports lazy image loading, loading prompt, and loading failure prompt.
import Vue from 'vue';
import { Image as VanImage } from 'vant';
Vue.use(VanImage);
Copy the code
Lazy image loading
To enable lazy image loading, set the lazy-load property in conjunction with the Lazyload component.
<van-image
width="100"
height="100"
lazy-load
src="https://img01.yzcdn.cn/vant/cat.jpeg"
/>
Copy the code
Card custom content
The Card component provides multiple slots for flexible customization of content.
< van - card num = "2" price = "2.00" desc = "description" title = "commodity title" thumb = "https://img01.yzcdn.cn/vant/ipad.jpeg" > < # template tags > </van-tag plain type="danger"> </van-tag plain type="danger"> </van-tag> </van-tag> </template> <template #footer> </van-button size="mini"> button </van-button> </van-button size="mini"> button </van-button> </template> </van-card>Copy the code
bass.css
@import "normalize.css";
:root{-color-text:# 666;
--color-high-text:pink;
--color-tint:pink;
--color-background:#FFFFFF;
--font-size:14px;
--line-height: 1.5; } *, *::before, *::after{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
user-select: none;
/*background-color: #FFFFFF; * /
background: var(--color-background);
color: var(--color-text);
width: 100vw;
}
a{
color: var(--color-text);
text-decoration: none;
}
.left{
float: left;
}
.right{
float: right;
}
/* Here set the size of the picture in the product details */
img{
max-width: 100%;
height: auto ;
}
Copy the code
detail.vue
<template>
<div>
<nav-bar>
<template v-slot:default>{{id}}</template>
</nav-bar>
<van-image style="margin-top: 50px"
width="100%"
lazy-load
:src="detail.cover_url"
/>
<van-card style="text-align: left"
:num="detail.stock"
:price="detail.price+'.00'"
:desc="detail.description"
:title="detail.title"
>
<template #tags>
<van-tag plain type="danger">A new book</van-tag>
<van-tag plain type="danger">recommended</van-tag>
</template>
<template #footer>
<van-button type="warning">Add to cart</van-button>
<van-button type="danger">Buy now</van-button>
</template>
</van-card>
<van-tabs v-model="active">
<van-tab title="Summary">
<div class="content" v-html="detail.details"><! {{detail. Details}}--> {{detail. Details}}-->
<! -- {{detail.details}}-->
</div>
</van-tab>
<van-tab title="Buzz">
</van-tab>
<van-tab title="Related Books">
<goods-list :goods="like_goods"></goods-list>
</van-tab>
</van-tabs>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import GoodsList from ".. /.. /components/content/goods/GoodsList";
import {useRoute} from 'vue-router'
import {ref,reactive,onMounted,toRefs} from 'vue'
import {getDetail} from ".. /.. /network/detail";
export default {
name: "Detail".components: {
NavBar,
GoodsList
},
setup(){
const route = useRoute()
let id = ref(0)
let book = reactive({
detail: {},like_goods: []// Similar books
})
//1 Mount the route
onMounted(() = >{
id.value = route.query.id
// 2 Add method, getDetail(), can receive id
getDetail(id.value).then(res= >{
// console.log(res)
book.detail = res.goods
book.like_goods = res.like_goods
// console.log(book.like_goods)})})return{ id, ... toRefs(book)/ / deconstruction}}}</script>
<style scoped lang="scss">
.content{
padding: 10px;
}
</style>
Copy the code
5 Project page – User interface
Authorization required (token)
1 user registered component development
Introduction of Form
It is used for data entry and verification, and supports input box, single box, check box, file upload and other types. It needs to be used with Field input box component. This component is supported in version 2.5.
import Vue from 'vue';
import { Form } from 'vant';
import { Field } from 'vant';
Vue.use(Form);
Vue.use(Field);
Copy the code
Basic usage
In the form, each Field component represents a form item, and the Field’s Rules property defines the validation rules.
<van-form @submit="onSubmit"> <van-field v-model="username" name=" username" label=" username" "placeholder=" username" :rules="[{ required: true, message: }]" /> < vain-field v-model="password" type="password" name=" password" label=" password" "placeholder=" password" :rules="[{required: "/> <div style="margin: 16px; </div> </van-form> </van-form>Copy the code
register.vue
<template>
<div>
<nav-bar>
<template v-slot:default>New user registration</template>
</nav-bar>
<div style="margin-top: 50px">
<div style="text-align: center; padding: 50px">
<van-image
width="10rem"
height="5rem"
fit="contain"
src="https://avatars.githubusercontent.com/u/49421343?s=60&v=4"
/>
</div>
<van-form @submit="onSubmit">
<van-field
v-model="name"
name="User name"
label="User name"
placeholder="User name"
:rules="[{required: true, message: 'Please fill in user name'}]"
/>
<van-field
v-model="password"
type="password"
name="Password"
label="Password"
placeholder="Password"
:rules="[{required: true, message: 'Please fill in password'}]"
/>
<van-field
v-model="password_confirmation"
type="password"
name="Confirm password"
label="Confirm password"
placeholder="Confirm password"
:rules="[{required: true, message: 'Please fill in the same password'}]"
/>
<van-field
v-model="email"
name="E-mail"
label="E-mail"
placeholder="Please enter the correct E-mail format"
:rules="[{required: true, message: 'Please fill in email'}]"
/>
<div style="margin: 16px;">
<van-button round block type="info" color="pink" native-type="submit">submit</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {ref,reactive,toRefs} from 'vue'
export default {
name: "Register".components:{
NavBar
},
setup(){
const userinfo = reactive({
name:' '.password:' '.password_confirmation:' '.email:' '
})
const onSubmit = () = >{
console.log('# # # #')// Front-end validation
}
return{
...toRefs(userinfo),
onSubmit
}
}
}
</script>
<style scoped>
</style>
Copy the code
2 User registration and authentication
register.vue
<template>
<div>
<nav-bar>
<template v-slot:default>New user registration</template>
</nav-bar>
<div style="margin-top: 50px">
<div style="text-align: center; padding: 50px">
<van-image
width="10rem"
height="5rem"
fit="contain"
src="https://avatars.githubusercontent.com/u/49421343?s=60&v=4"
/>
</div>
<van-form @submit="onSubmit">
<van-field
v-model="name"
name="User name"
label="User name"
placeholder="User name"
:rules="[{required: true, message: 'Please fill in user name'}]"
/>
<van-field
v-model="password"
type="password"
name="Password"
label="Password"
placeholder="Password"
:rules="[{required: true, message: 'Please fill in password'}]"
/>
<van-field
v-model="password_confirmation"
type="password"
name="Confirm password"
label="Confirm password"
placeholder="Confirm password"
:rules="[{required: true, message: 'Please fill in the same password'}]"
/>
<van-field
v-model="email"
name="E-mail"
label="E-mail"
placeholder="Please enter the correct E-mail format"
:rules="[{required: true, message: 'Please fill in email'}]"
/>
<div style="margin: 16px;">
<van-button round block type="info" color="pink" native-type="submit">submit</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {ref,reactive,toRefs} from 'vue';
import {register} from ".. /.. /network/user";
import {Notify,Toast} from 'vant';// The notification method is Toast
import {useRouter} from 'vue-router'
export default {
name: "Register".components:{
NavBar
},
setup(){
const router = useRouter()
const userinfo = reactive({
name:' '.password:' '.password_confirmation:' '.email:' '
})
const onSubmit = () = >{
// console.log('####')// Response intercept
// 1
if(userinfo.password ! = userinfo.password_confirmation) { Notify('Two passwords don't match... ');
}else {
// Submit again, return all submitted data, and
register(userinfo).then((res) = > {
if (res.status === 201) {
Toast.success("Registration successful");
setTimeout(() = > {
// After successful registration, the login page will be redirected to 1 second
router.push({ path: "/login" });
}, 1000);
}
// Clear the password form
userinfo.password = "";
userinfo.password_confirmation = "";
});
}
// 2 Submit to the backend
}
return{
...toRefs(userinfo),
onSubmit,
}
}
}
</script>
<style scoped>
</style>
Copy the code
request.js
import axios from 'axios';
import { Notify } from 'vant';// Message notification method
export function request(config) {
const instance = axios.create({
baseURL:'https://api.shop.eduwork.cn'.timeout:5000
})
// Request interception
instance.interceptors.request.use(config= >{
// If there is an interface that requires authentication to access, set it in a unified way, (token)
// Direct release
return config
},error= >{})// Response intercept
instance.interceptors.response.use(res= >{
// console.log(res)
return res.data ? res.data : res
},err= > {
// If the interfaces that can be accessed only by authorization, disable login authorization
// If there is an error, handle it here and determine the type of error based on the status code.
// console.log(err.response.data.errors[Object.keys(err.response.data.errors)][0])
Notify(err.response.data.errors[Object.keys(err.response.data.errors)[0]] [0]);
})
return instance(config)
}
Copy the code
3 User login development
Login.vue
<template>
<div>
<nav-bar>
<template v-slot:default>The user login</template>
</nav-bar>
<div style="margin-top: 50px">
<div style="text-align: center; padding: 50px">
<van-image
width="10rem"
height="5rem"
fit="contain"
src="https://avatars.githubusercontent.com/u/49421343?s=60&v=4"
/>
</div>
<van-form @submit="onSubmit">
<van-field
v-model="email"
name="email"
label="email"
placeholder="email"
:rules="[{required: true, message: 'Email please'}]"
/>
<van-field
v-model="password"
type="password"
name="Password"
label="Password"
placeholder="Password"
:rules="[{required: true, message: 'Please fill in password'}]"
/>
<div style="margin: 16px;">
<div class="link_login" @click="$router.push({path:'/register'})">No account, sign up now</div>
<van-button round block type="info" color="pink" native-type="submit">submit</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
// Username: eduwork2 Password: user123 Email: [email protected]
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {ref,reactive,toRefs} from 'vue';
import {login} from ".. /.. /network/user";
import {Notify,Toast} from 'vant';// The notification method is Toast
import {useRouter} from 'vue-router'
export default {
name: "Login".components:{
NavBar
},
setup(){
const router = useRouter()
const userinfo = reactive({
email:' '.password:' ',})const onSubmit = () = >{
// console.log('####')// Response intercept
// Bidirectional binding
login(userinfo).then(res= >{
LocalStorage setItem(key,value) getItem(key); //1, the server will return token: acess -token, save the token to local, window.localstorage setItem(key,value) getItem(key)
window.localStorage.setItem('token',res.access_token)
// (or) in vuex islogin judge save
Toast.success('Login successful')
userinfo.email=' '
userinfo.password=' '
setTimeout(() = >{
router.go(-1)},500)
//})}return{
...toRefs(userinfo),
onSubmit
}
}
}
</script>
<style scoped>
.link_login{
font-size: 14px;
margin-bottom: 20px;
color: # 990055;
display: inline-block;
text-align: left;
float: left;
}
</style>
Copy the code
user.js
// All is related to the user
/ / register
/ / login
/ / verification
import {request} from "./request";
export function register(data) {
return request({
url:'/api/auth/register'.method:'post',
data
})
}
export function login(data) {
return request({
url:'/api/auth/login'.method:'post',
data
})
}
Copy the code
4 User Login Authorization Scheme Processing
There are two authorization schemes:
1. Page level authorization
2. Interface-level authorization
Profile. vue builds the personal interface first
<template>
<div>
<nav-bar>
<template v-slot:default>Personal home page</template>
</nav-bar>
<div style="margin:15px; margin-top: 100px">
<van-button @click="tologout" round block color="pink">Log out</van-button>
</div>
</div>
</template>
<script>
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {logout} from ".. /.. /network/user";
import {Toast} from 'vant'
import {useRouter} from 'vue-router'
import {useStore} from 'vuex'
export default {
name: "Profile".components: {
NavBar
},
setup(){
const router = useRouter()
const tologout =() = >{
logout().then(res= >{
if (res.status === 204) {
Toast.success('Exit successfully')
// Clear the token window. localStorage
window.localStorage.setItem('token'.' ')
store.commit('setIsLogin'.false)
setTimeout(() = >{
router.push({path:'/login'})},500)}}}return{
tologout,
}
}
}
</script>
<style scoped>
</style>
Copy the code
router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const Home = () = > import('.. /views/home/Home.vue')
const Category = () = > import('.. /views/category/Category.vue')
const Detail = () = > import('.. /views/detail/Detail.vue')
const Profile = () = > import('.. /views/profile/Profile.vue')
const ShopCart = () = > import('.. /views/shopcart/ShopCart.vue')
const Register =() = >import('.. /views/profile/Register.vue')
const Login =() = >import('.. /views/profile/Login.vue')
import store from '.. /store'
import {Notify, Toast} from 'vant'
/ / write routing
const routes = [
{
path: ' '.name: 'DefaultHome'.component: Home,
meta: {title:'fy-shop'}}, {path: '/'.name: 'Home'.component: Home,
meta: {title:'fy-shop'}}, {path: '/category'.name: 'Category'.component: Category,
meta: {title:'Classification'}}, {path: '/detail'.name: 'Detail'.component: Detail,
meta: {title:'Product Details'
}
},{
path: '/profile'.name: 'Profile'.component: Profile,
meta: {title:'Personal center'.isAuthRequired:true
}
},{
path: '/register'.name: 'Register'.component: Register,
meta: {title:'User registration',}}, {path: '/login'.name: 'Login'.component: Login,
meta: {title:'User Login'
}
},{
path: '/shopcart'.name: 'ShopCart'.component: ShopCart,
meta: {title:'Shopping cart'.isAuthRequired:true}}]const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to,from,next) = >{
// If there is no login, go to login here
if (to.meta.isAuthRequired && store.state.user.isLogin === false) {// Give a hint
Notify('Not logged in yet, please log in')
return next('/login')}else {
next()
}
document.title = to.meta.title
}
)
export default router
Copy the code
Login.vue
<template>
<div>
<nav-bar>
<template v-slot:default>The user login</template>
</nav-bar>
<div style="margin-top: 50px">
<div style="text-align: center; padding: 50px">
<van-image
width="10rem"
height="5rem"
fit="contain"
src="https://avatars.githubusercontent.com/u/49421343?s=60&v=4"
/>
</div>
<van-form @submit="onSubmit">
<van-field
v-model="email"
name="email"
label="email"
placeholder="email"
:rules="[{required: true, message: 'Email please'}]"
/>
<van-field
v-model="password"
type="password"
name="Password"
label="Password"
placeholder="Password"
:rules="[{required: true, message: 'Please fill in password'}]"
/>
<div style="margin: 16px;">
<div class="link_login" @click="$router.push({path:'/register'})">No account, sign up now</div>
<van-button round block type="info" color="pink" native-type="submit">submit</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
// Username: eduwork2 Password: user123 Email: [email protected]
import NavBar from ".. /.. /components/common/navbar/NavBar";
import {ref,reactive,toRefs} from 'vue';
import {login} from ".. /.. /network/user";
import {Notify,Toast} from 'vant';// The notification method is Toast
import {useRouter} from 'vue-router'
import {useStore} from 'vuex'
export default {
name: "Login".components:{
NavBar
},
setup(){
const router = useRouter()
const store = useStore()
const userinfo = reactive({
email:' '.password:' ',})const onSubmit = () = >{
// Bidirectional binding
login(userinfo).then(res= >{
LocalStorage setItem(key,value) getItem(key); //1, the server will return token: acess -token, save the token to local, window.localstorage setItem(key,value) getItem(key)
window.localStorage.setItem('token',res.access_token)
// (or) in vuex islogin judge save
store.commit('setIsLogin'.true)
Toast.success('Login successful')
userinfo.email=' '
userinfo.password=' '
setTimeout(() = >{
router.go(-1)},500)
//})}return{
...toRefs(userinfo),
onSubmit
}
}
}
</script>
<style scoped>
.link_login{
font-size: 14px;
margin-bottom: 20px;
color: # 990055;
display: inline-block;
text-align: left;
float: left;
}
</style>
Copy the code
request.js
import axios from 'axios';
import { Notify,Toast } from 'vant';
import router from ".. /router";
// Message notification method
export function request(config) {
const instance = axios.create({
baseURL:'https://api.shop.eduwork.cn'.timeout:5000
})
// Request interception
instance.interceptors.request.use(config= >{
// If there is an interface that requires authentication to access, set it in a unified way, (token)
const token = window.localStorage.getItem('token')
if (token) {
/ / headers
config.headers.Authorization = 'Beater'+token
}
// Direct release
return config
},error= >{})// Response intercept
instance.interceptors.response.use(res= >{
// console.log(res)
return res.data ? res.data : res
},err= > {
// If the interfaces that can be accessed only by authorization, disable login authorization
if (err.response.status == '401'){
Toast.fail('Please login first')
router.push({path:'/login'})}// If there is an error, handle it here and determine the type of error based on the status code.
// console.log(err.response.data.errors[Object.keys(err.response.data.errors)][0])
Notify(err.response.data.errors[Object.keys(err.response.data.errors)[0]] [0]);
})
return instance(config)
}
Copy the code
store
store/index.js
import { createStore } from 'vuex'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
const state = {
user: {isLogin:window.localStorage.getItem('token')? true:false}}export default createStore({
state,
mutations,
actions,
getters
})
Copy the code
mutations.js
const mutations ={
setIsLogin(state,payload){
state.user.isLogin = payload
}
}
export default mutations
Copy the code
actions.js
const actions = {
}
export default actions
Copy the code
getters.js
const getters = {
}
export default getters
Copy the code