插件全局注册
通用性组件通过插件方式全局注册
index.js:
//component中所有组件全局注册
//通过插件方式
import imgView from './imageView/index.vue'
import Sku from './XtxSku/index.vue'
export const componentPlugins = {
install(app) {
//app.component('组件名字',组件的配置对象)
app.component('imgView', imgView)
app.component('Sku', Sku)
}
}
main.js:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
// 引入样式
import '@/styles/common.scss'
//引入懒加载指令插件
import { lazyPlugin } from './directives'
import { componentPlugins } from './components/index'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(lazyPlugin)
app.use(componentPlugins)
app.mount('#app')
注册持久化插件:xxx.use()
懒加载插件
import { useIntersectionObserver } from '@vueuse/core'
export const lazyPlugin = {
install(app) {
app.directive('img-lazy', {
mounted(el, binding) {
// el:绑定的元素
// binding:binding.value 指令等号后面的表达式的值
console.log(el, binding);
const { stop } = useIntersectionObserver(
el,
([{ isIntersecting }]) => {
console.log(isIntersecting)
if (isIntersecting) {
// 进入视口区域
el.src = binding.value
stop()
}
},
)
}
})
}
}
asios基础配置
http.js:
import axios from "axios";
const httpInstance = axios.create({
baseURL: 'http://xxxx',
timeout: 5000,
})
// 添加请求拦截器
httpInstance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
httpInstance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
export default httpInstance
api.js
import httpInstance from "@/utils/http";
export function getBannerAPI(params = {}) {
const { distributionSite = '1' } = params
return httpInstance({
url: '/home/banner',
params: {
distributionSite
}
})
}
banner.vue:
const bannerList = ref([])
const getBanner = async ()=>{
const res = await getBannerAPI()
// console.log(res);
bannerList.value = res.data.result
}
onMounted(()=>{
getBanner()
})
请求拦截器携带token
// 添加请求拦截器
httpInstance.interceptors.request.use(function (config) {
const userStore = useUserStore()
const token = userStore.userInfo.token
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
- 从pinia中取出token数据
- 按照后端要求拼接token数据
响应拦截器处理失效token
// 添加响应拦截器
httpInstance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
//统一错误提示
console.log(error)
ElMessage({
type: 'warning',
message: error.response.data.message
})
//401 token失效处理
if (error.response.status === 401) {
const userStore = useUserStore()
userStore.clearUserInfo()
const router = useRouter()
router.push('/login')
}
return Promise.reject(error);
});
Pinia配置
import { ref } from 'vue'
import { getCategoryAPI } from '@/apis/layoutApi.js'
import { defineStore } from 'pinia'
export const useCategoryStore = defineStore('category', () => {
//导航列表的逻辑
const categoryList = ref([])
const getCategory = async () => {
const res = await getCategoryAPI()
// console.log(res);
categoryList.value = res.data.result
}
return { categoryList, getCategory }
})
使用:
import { useCategoryStore } from '@/stores/category';
const categoryStore = useCategoryStore()
- defineStore导入并使用:defineStore(‘模块名’, ()=> {})
- Pinia 包括两个部分:数据state和 获取数据接口action
- 最后以对象格式将state和action return出去
pinia数据持久化
pinia-plugin-persistedstate
运行机制:在设置state的时候自动把数据同步给localstorage,在获取state 数据的同时会优先从localstorage中取出
路由配置
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/Login/index.vue'
import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue'
import Category from '@/views/Category/index.vue'
import SubCategory from '@/views/subCategory/index.vue'
import GoodsDetails from '@/views/Details/index.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
//一级配置
{
path: '/',
component: Layout,
//二级配置
children: [
{
path: '',
component: Home,
},
{
path: 'category/:id',
component: Category
},
{
path: 'category/sub/:id',
component: SubCategory
},
{
path: 'detail/:id',
component: GoodsDetails
}
]
},
{
path: '/login',
component: Login
}
],
//路由滚动行为定制
scrollBehavior() {
return { top: 0 }
}
})
export default router
组件封装
<script setup>
defineProps({
title:{
type:String
},
subtitle:{
type:String
}
})
</script>
<template>
<div class="home-panel">
<div class="container">
<div class="head">
<!-- 主标题和副标题 -->
<h3>
{{title}}<small>{{subtitle}}</small>
</h3>
</div>
<!-- 主体内容区域 -->
<slot> </slot>
</div>
</div>
</template>
<style>
</style>
使用:
<HomePanel title="人气推荐" subtitle="人气爆款 不容错过">
<ul class="goods-list">
<li v-for="item in hotList" :key="item.id">
<RouterLink to="/">
<img v-img-lazy="item.picture" alt="">
<p class="name">{{ item.title }}</p>
<p class="desc">{{ item.alt }}</p>
</RouterLink>
</li>
</ul>
</HomePanel>
表单绑定
import { ref } from 'vue'
import { loginApi } from '@/apis/userApi'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
import { useRouter } from 'vue-router'
import router from '@/router'
//表单校验:账户名和密码
const form = ref({
accounr: '',
password: '',
agree: true,
})
//准备规则对象
const rules = {
account: [
{ required: true, message: '用户名不能为空', trigger: 'blur' }
],
password: [
{ required: true, message: '密码不能为空', trigger: 'blur' },
{ min: 6, max: 14, message: '密码为6到14位', trigger: 'blur' }
],
agree: [
{
validator: (rule, value, callback) => {
console.log(value);
//自定义校验逻辑
if (value) {
callback()
}
else {
callback(new Error('请勾选协议'))
}
}
}
]
}
//获取form实例
const formRef = ref(null)
const subform = () => {
const Router = useRouter()
formRef.value.validate(async (valid) => {
//表单都通过校验 valid才true
if (valid) {
const { account, password } = form.value
const res = await loginApi({ account, password })
console.log(res);
ElMessage({ type: 'success', message: '登录成功' })
router.replace({ path: '/' })
}
})
}
</script>
<template>
<section class="login-section">
<div class="wrapper">
<nav>
<a href="javascript:;">账户登录</a>
</nav>
<div class="account-box">
<div class="form">
<el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-width="60px" status-icon>
<el-form-item prop="account" label="账户">
<el-input v-model="form.account" />
</el-form-item>
<el-form-item prop="password" label="密码">
<el-input v-model="form.password" />
</el-form-item>
<el-form-item label-width="22px" prop="agree">
<el-checkbox size="large" v-model="form.agree">
我已同意隐私条款和服务条款
</el-checkbox>
</el-form-item>
<el-button size="large" class="subBtn" @click="subform">点击登录</el-button>
</el-form>
</div>
</div>
</div>
</section>
- 表单数据绑定 :model=“form”
- 准备规则对象 el-form上绑定:rules=“rules” item上绑定 prop=“account”
- 自定义校验逻辑 validator: (rule, value, callback) => {}
- 获取form实例 提交时进行全部规则检验 formRef.value.validate
- 获取当前路由 const Router = useRouter()
useRouter是方法,useRoute是获取参数
直接跳转 @click=‘$router.push(‘./xxx’)’·