Article directory
- axios package
-
- http.js
- testAPI.js
- main.js test
- If multiple baseURLs are required in the project
- Import scss files automatically
-
- case file
- Use Cases
- Introduce aliyun icon library
-
- first look at the effect
- View official website documents
- import and use
- Vueuse implementation – adsorption navigation interaction
-
- Install
- the case
- Requests, data, and encapsulation shared by multiple components to pinia
-
- the case
- Called from parent component
- Applied in subcomponents
- Resource lazy loading case (vue3 custom instruction & amp;vueuse)
-
- case simulation
-
- main.js
- components
- Lazy loading module optimization
-
- main.js
- Lazy loading code optimization
-
- Effect
- When the routing url changes, the current routing is forced to be destroyed and rebuilt, which can be used for primary or secondary routing
-
- The method of using key (simple and easy to use)
-
- Effect demonstration
- onBeforeRouteUpdate navigation hook
-
- sample code
- Drag the webpage to the bottom and load data resources wirelessly
-
- v-infinite-scoll
- Event case
- Effect demonstration
- Make the user view jump to the top when the route is switched
-
- edit router.js
- Effect view
- Use of third-party components
-
- Sku component case
-
- Sku component concept
- Component Usage Tips
- token timeliness processing
-
- Encounter problems
- solution
- Test token invalidation effect, manually modify token
- Response interceptor handles 401
- test
Axios package
http.js
//Axios basic encapsulation import axios from 'axios' const httpInstance = axios.create({<!-- --> baseURL: 'http://pcapi-xiaotuxian-front-devtest.iheima.net', timeout: 5000 }) //Interceptor // add request interceptor httpInstance.interceptors.request.use(function (config) {<!-- --> return config; }, function (error) {<!-- --> return Promise. reject(error); }); // add response interceptor httpInstance.interceptors.response.use(function (response) {<!-- --> return response; }, function (error) {<!-- --> return Promise. reject(error); }); export default httpInstance
testAPI.js
import httpInstance from "@/utils/http"; export function getCategory(){<!-- --> return httpInstance({<!-- --> url:'home/category/head' }) }
main.js test
//Test interface function import {<!-- -->getCategory} from "@/apis/testAPI"; getCategory().then (res => {<!-- --> console. log(res) })
If multiple baseURLs are required in the project
Automatically import scss files
Case file
$xtxColor: #27ba9b; $helpColor: #e26237; $sucColor: #1dc779; $warnColor: #ffb302; $priceColor: #cf4444;
Use case
<!--setup-switch: Allow writing combined API in script--> <script setup> </script> <template> <div> <el-button type="primary">Primary</el-button> <!--Level 1 routing exit--> <RouterView /> <div class="test"> test scss </div> </div> </template> <style scoped lang="scss"> .test{<!-- --> color:$warnColor; } </style>
Introduce aliyun icon library
Look at the effect first
View official website documents
Official document description
Import and use
If there is no index.html, just create a new one
Note that the content needs to be replaced
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="icon" href="/favicon.ico"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vite App</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css"> </head> <body> <div id="app"> </div> <script type="module" src="/src/main.js"></script> </body> </html>
use
vueuse implementation – adsorption navigation interaction
Install
npm i @vueuse/core
Case
In this case, a new component is generated and rendered on the page according to certain conditions
Specifically, when the scroll position y is greater than 78, the element adds the show class.
In the CSS section, there is a CSS class definition named .show. This class is used to apply styles when the app-header-sticky element has the show class. These styles include a 0.3-second linear transition for the transition, a default value for the transform, and an opacity of 1.
Therefore, depending on whether the scroll position y is greater than 78, the app-header-sticky element will dynamically add or remove the show class, triggering transition effects and style changes.
core code
<script setup> // vueUse import {<!-- --> useScroll } from '@vueuse/core' const {<!-- --> y } = useScroll(window) </script> <template> <div class="app-header-sticky" :class="{show:y > 78}"> <div class="container"> <RouterLink class="logo" to="/" /> <!-- Navigation area --> <ul class="app-header-nav"> <li class="home"> <RouterLink to="/">Homepage</RouterLink> </li> <li> <RouterLink to="/">Home</RouterLink> </li> <li> <RouterLink to="/">Gourmet</RouterLink> </li> <li> <RouterLink to="/">Apparel</RouterLink> </li> <li> <RouterLink to="/">Mother and Child</RouterLink> </li> <li> <RouterLink to="/">personal care</RouterLink> </li> <li> <RouterLink to="/">Selection</RouterLink> </li> <li> <RouterLink to="/">Digital</RouterLink> </li> <li> <RouterLink to="/">Motion</RouterLink> </li> <li> <RouterLink to="/">Miscellaneous</RouterLink> </li> </ul> <div class="right"> <RouterLink to="/">Brand</RouterLink> <RouterLink to="/">Theme</RouterLink> </div> </div> </div> </template> <style scoped lang='scss'> .app-header-sticky {<!-- --> width: 100%; height: 80px; position: fixed; left: 0; top: 0; z-index: 999; background-color: #fff; border-bottom: 1px solid #e4e4e4; // This is the key style!!! // State 1: translate its own height up + fully transparent transform: translateY(-100%); opacity: 0; // state two: remove translation + full opacity &.show {<!-- --> transition: all 0.3s linear; transform: none; opacity: 1; } .container {<!-- --> display: flex; align-items: center; } .logo {<!-- --> width: 200px; height: 80px; background: url("@/assets/images/logo.png") no-repeat right 2px; background-size: 160px auto; } .right {<!-- --> width: 220px; display: flex; text-align: center; padding-left: 40px; border-left: 2px solid $xtxColor; a {<!-- --> width: 38px; margin-right: 40px; font-size: 16px; line-height: 1; &:hover {<!-- --> color: $xtxColor; } } } } .app-header-nav {<!-- --> width: 820px; display: flex; padding-left: 40px; position: relative; z-index: 998; li {<!-- --> margin-right: 40px; width: 38px; text-align: center; a {<!-- --> font-size: 16px; line-height: 32px; height: 32px; display: inline-block; &:hover {<!-- --> color: $xtxColor; border-bottom: 1px solid $xtxColor; } } .active {<!-- --> color: $xtxColor; border-bottom: 1px solid $xtxColor; } } } </style>
Requests, data shared by multiple components, encapsulated into pinia
Case
Encapsulate the following request
import {<!-- --> ref } from 'vue' import {<!-- --> defineStore } from 'pinia' import {<!-- --> getCategoryAPI } from '@/apis/layout' export const useCategoryStore = defineStore('category', () => {<!-- --> // Data management of the navigation list // state navigation list data const categoryList = ref([]) // action method to get navigation data const getCategory = async () => {<!-- --> const res = await getCategoryAPI() categoryList.value = res.data.result } return {<!-- --> categoryList, getCategory } })
Called in parent component
//trigger the action to get the navigation list import {<!-- -->useCategoryStore} from "@/stores/categoryStore"; import {<!-- -->onMounted} from "vue"; const categoryStore = useCategoryStore(); onMounted(() => categoryStore. getCategory())
Application in subcomponents
Use the state after changing the data
<script setup> import {<!-- --> useCategoryStore } from '@/stores/categoryStore' const categoryStore = useCategoryStore() </script> <template> <ul class="app-header-nav"> <li class="home"> <RouterLink to="/">Homepage</RouterLink> </li> <li class="home" v-for="item in categoryStore.categoryList" :key="item.id"> <RouterLink active-class="active" :to="`/category/${item.id}`"> {<!-- -->{<!-- --> item.name }} </RouterLink> </li> </ul> </template>
Resource lazy loading case (vue3 custom instruction & amp;vueuse)
Case simulation
main.js
import {<!-- --> useIntersectionObserver } from '@vueuse/core' //Define global directives app.directive('img-lazy',{<!-- --> mounted(el,binding){<!-- --> //el: the element img bound by the instruction // binding: binding.value command is equal to the value of the expression bound after the sign image url console.log(el,binding.value) useIntersectionObserver( el, ([{<!-- --> isIntersecting }]) => {<!-- --> console. log(isIntersecting) if(isIntersecting){<!-- --> // enter the viewport area el.src = binding.value } }, ) } })
Component
core content
<script setup> import HomePanel from './HomePanel.vue' import {<!-- -->getHotAPI} from '@/apis/home' import {<!-- -->ref} from 'vue' const hotList = ref([]) const getHotList = async () => {<!-- --> const res = await getHotAPI() console. log(res) hotList.value = res.data.result } getHotList() </script> <template> <HomePanel title="Popular recommendation" sub-title="Popular hot style, not to be missed"> <template #main> <ul class="goods-list"> <li v-for="item in hotList" :key="item.id"> <RouterLink to="/"> <!-- <img :src="item.picture" alt="">--> <img v-img-lazy="item. picture" alt=""> <p class="name">{<!-- -->{<!-- --> item.title }}</p> <p class="desc">{<!-- -->{<!-- --> item.alt }}</p> </RouterLink> </li> </ul> </template> </HomePanel> </template> <style scoped lang='scss'> .goods-list {<!-- --> display: flex; justify-content: space-between; height: 426px; li {<!-- --> width: 306px; height: 406px; transition: all .5s; &:hover {<!-- --> transform: translate3d(0, -3px, 0); box-shadow: 0 3px 8px rgb(0 0 0 / 20%); } img {<!-- --> width: 306px; height: 306px; } p {<!-- --> font-size: 22px; padding-top: 12px; text-align: center; } .desc {<!-- --> color: #999; font-size: 18px; } } } </style>
Lazy loading module optimization
separate file
// Define lazy loading plugin import {<!-- -->useIntersectionObserver} from "@vueuse/core"; export const lazyPlugin = {<!-- --> install(app) {<!-- --> //lazy loading instruction logic app.directive('img-lazy', {<!-- --> mounted(el, binding) {<!-- --> //el: the element img bound by the instruction // binding: binding.value command is equal to the value of the expression bound after the sign image url console. log(el, binding. value) const {<!-- -->stop} = useIntersectionObserver( el, ([{<!-- -->isIntersecting}]) => {<!-- --> console. log(isIntersecting) if (isIntersecting) {<!-- --> // enter the viewport area el.src = binding.value // Don't re-judge after loading stop() } }, ) } }) } }
main.js
Lazy loading code optimization
// Define lazy loading plugin import {<!-- -->useIntersectionObserver} from "@vueuse/core"; export const lazyPlugin = {<!-- --> install(app) {<!-- --> //lazy loading instruction logic app.directive('img-lazy', {<!-- --> mounted(el, binding) {<!-- --> //el: the element img bound by the instruction // binding: binding.value command is equal to the value of the expression bound after the sign image url console. log(el, binding. value) const {<!-- -->stop} = useIntersectionObserver( el, ([{<!-- -->isIntersecting}]) => {<!-- --> console. log(isIntersecting) if (isIntersecting) {<!-- --> // enter the viewport area el.src = binding.value // Don't re-judge after loading stop() } }, ) } }) } }
Effect
No reloading after loading, saving resources
When the routing url changes, the current routing is forced to be destroyed and rebuilt, which can be used for primary or secondary routing
The method of using key (simple and easy to use)
<RouterView :key="$route.fullPath"/>
Effect demonstration
onBeforeRouteUpdate navigation hook
- Executed before each route update
Example code
onBeforeRouteUpdate( (to) => {<!-- --> //to represents the target object console. log(to) getCategory(to.params.id) })
Our original method needs to re-accept parameters
//id is the default parameter const getCategory = async (id = route.params.id) => {<!-- --> const res = await getTopCategoryAPI(id) categoryData.value = res.data.result }
Drag the webpage to the bottom, wirelessly load data resources
Use a property of element plus
v-infinite-scoll
<div class="body" v-infinite-scroll="load" :infinite-scroll-disabled="disabled"> <!-- product list --> <goods-item v-for="goods in goodList" :goods="goods" :key="goods.id"></goods-item> </div>
Event case
// load more const disabled = ref(false) const load = async () => {<!-- --> console.log('load more data') // Get the data of the next page reqData.value.page++ const res = await getSubCategoryAPI(reqData. value) goodList.value = [...goodList.value, ...res.data.result.items] // After loading, stop listening if (res.result.items.length === 0) {<!-- --> disabled. value = true } }
Effect demonstration
Make the user view jump to the top when the route is switched
Edit router.js
scrollBehavior(){<!-- --> return {<!-- -->top:0} }
Effect view
Use of third-party components
Sku component case
Sku component concept
Stock keeping unit (English: stock keeping unit, SKU/s?keju?/), also translated as stock keeping unit, is an accounting term defined as inventory management
The smallest available unit, for example, a SKU in textiles usually refers to specifications, colors, and styles, while in chain retail stores, a single product is sometimes referred to as an SKU
The role of the SKU component: output the product specifications selected by the current user, and provide data information for the operation of adding to the shopping cart
Component usage skills
Question: In actual work, I often encounter components written by others, and I am familiar with a third-party component. What should I focus on first?
Answer: props and emit, props determines what data the current component receives, and emit determines what data will be produced
Token timeliness processing
I have a problem
The validity of the token can be maintained for a certain period of time. If the user does not perform any operations for a period of time, the token will become invalid. If the invalid token is used to request some interfaces, the interface will report a 401 status code error, which requires us to do additional processing
two questions to think about
- Can we determine which interface the user is accessing the 401 error? Where to intercept this 401?
- What should I do after detecting 401?
Solution
Do unified processing in the axios response interceptor
- Intercept 401 in failure callback
- Clear out expired user information
- Jump to login page
Test token invalidation effect, manually modify token
refresh page
View console 401
Response interceptor handles 401
httpInstance.interceptors.response.use(function (response) {<!-- --> return response; }, function (error) {<!-- --> ElMessage({<!-- --> type:'warning', message:error.response.data.msg }) // 401 token invalidation processing // 1. Clear local user data // 2. Jump to the login page if(error.response.status === 401){<!-- --> const userStore = useUserStore() //Call action to change states and clear user data userStore. clearUserInfo() //jump to login page router. push('/login') } return Promise. reject(error); });
Test
It is still the above steps, but here the background should only do token verification on the goods path of detail, so it can only be tested on the product details page
- Log in
- Manually modify the token
- Refresh the page at http://localhost:5173/detail/4020262