本文主要將如何利用搭建一個初始化的商城H5項(xiàng)目框架。初始化階段使用的技術(shù)棧有:vue3.2、vue-router、?TS 、 Pinia 、 Vant4、Less、vite
1. 環(huán)境檢測:
????????????????????????node -v 檢測是否有安裝node.js,未安裝請先去官網(wǎng)安裝node.js
2. 創(chuàng)建初始化項(xiàng)目:?
? ? ? ? 終端輸入:?npm?init vite
????????自定義項(xiàng)目名稱project name:demodemo
? ? ? ? 依次選擇Vue + TypeScript創(chuàng)建項(xiàng)目
???????啟動項(xiàng)目:???cd demodemo
????????????????????????????????npm install
????????????????????????????????npm run dev
3. 初始化項(xiàng)目文件
刪除style.css文件,清空assets文件和components文件
新增request文件(配置網(wǎng)絡(luò)請求和集中存儲請求API),文件下新建index.ts和api.ts兩個空文件?
新增store文件(數(shù)據(jù)共享倉庫),文件下新建index.ts和order.ts和address.ts三個空文件?
新增views文件(集中存放各頁面),文件下新建Home.vue和Login.vue和404.vue等空文件?
新增types文件(聲明TS類型),文件下新建api.d.ts一個空文件
?處理App.vue文件
//App.vue
<script setup lang="ts">
</script>
<template>
//路由占位符
<router-view />
</template>
<style scoped lang="less">
</style>
?處理main.ts文件
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
4. 樣式初始化,引入vant組件庫,瀏覽器適配
1)樣式初始化
? ? ? ? npm i reset-css
//在main.ts中引入
import "reset-css" //樣式初始化
2)引入vant組件庫
????????npm i vant
//在main.ts中引入vant
import vant from "vant"
import "../node_modules/vant/lib/index.css"
3)瀏覽器適配
? ? ? ? npm i postcss-px-to-viewport --save -dev
新建文件postcss.config.cjs,配置設(shè)計(jì)稿的視口寬度:viewportWidth: 375,其余可選配置
//postcss.config.cjs文件
module.exports = {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: 375, // 設(shè)計(jì)稿的視口寬度
unitPrecision: 5, // 單位轉(zhuǎn)換后保留的精度
propList: ["*"], // 能轉(zhuǎn)化為vw的屬性列表
viewportUnit: "vw", // 希望使用的視口單位
fontViewportUnit: "vw", // 字體使用的視口單位
selectorBlackList: [], // 需要忽略的CSS選擇器,不會轉(zhuǎn)為視口單位,使用原有的px等單位。
minPixelValue: 1, // 設(shè)置最小的轉(zhuǎn)換數(shù)值,如果為1的話,只有大于1的值會被轉(zhuǎn)換
mediaQuery: false, // 媒體查詢里的單位是否需要轉(zhuǎn)換單位
replace: true, // 是否直接更換屬性值,而不添加備用屬性
exclude: undefined, // 忽略某些文件夾下的文件或特定文件,例如 'node_modules' 下的文件
include: undefined, // 如果設(shè)置了include,那將只有匹配到的文件才會被轉(zhuǎn)換
landscape: false, // 是否添加根據(jù) landscapeWidth 生成的媒體查詢條件 @media (orientation: landscape)
landscapeUnit: "vw", // 橫屏?xí)r使用的單位
landscapeWidth: 568, // 橫屏?xí)r使用的視口寬度
},
},
};
5. 自動導(dǎo)入常用的使用的第三方庫的 API
npm i -D unplugin-auto-import
//在vite.config.ts中配置
import AutoImport from "unplugin-auto-import/vite"
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: [ 'vue', 'vue-router'] //自動導(dǎo)入相關(guān)函數(shù)
})
],
})
6. 配置網(wǎng)絡(luò)請求,全局配置請求的參數(shù)和返回值TS類型
? ? ? ? npm i axios
//在request文件下的index.ts配置
import axios from "axios"
const instance = axios.create({
baseURL: "https://XXXXXX.com",
timeout: 20000
})
//請求攔截器
instance.interceptors.request.use(
config => {
if(localStorage.getItem('token')){
config.headers.Authorization = localStorage.getItem('token')
}
return config
},
err => {
return Promise.reject(err)
}
)
// 響應(yīng)攔截器
instance.interceptors.response.use(
res => {
return res.data
},
err => {
return Promise.reject(err)
}
)
export default instance
//在request文件下的api.ts配置
import request from "./index"
export const helpCenterRes = () => request.get('/helpcenter')
export const bannerAPIRes = ( params: BannerAPIReq ):Promise<BannerAPIRes> => request.get('/banner', {params})
在types文件下api.d.ts,配置各個請求接口的參數(shù)類型和返回值類型,并在api.ts中應(yīng)用
interface BannerAPIReq {
title: string;
}
interface BannerListType {
detail_url: string;
picture: string;
url: string;
}
interface BannerAPIRes {
code: number;
message: string;
banner: BannerListType[];
}
//在Index.vue中使用封裝的接口
<script setup lang="ts">
import { ref,onMounted } from "vue"
import { bannerAPIRes } from '../request/api'
onMounted( () => {
getBannerRes()
})
interface BannerListType {
detail_url: string;
picture: string;
url: string;
}
const bannerList = ref<BannerListType[]>([])
const getBannerRes = async() => {
const res:any = await bannerAPIRes({
title: 'newapp'
})
console.log(res)
if(res.code == 200){
bannerList.value = res.banner
}
}
</script>
<template>
<van-swipe :autoplay="3000" :height="420" lazy-render>
<van-swipe-item v-for="item in bannerList">
<img style="width: 100%;height: 419.4px;" :src="item.picture" />
</van-swipe-item>
</van-swipe>
</template>
<style scoped lang="less">
</style>
7. ?配置路由
npm i vue-router ? ? ? ? ?//下載vue-router插件第四版本
//main.ts中引入和掛載路由
import router from './router'
app.use(router)
//router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import Home from "../views/Home.vue"
import Index from "../views/Index.vue"
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Home,
redirect: '/index', //路由重定向
children: [ //路由嵌套
{
path: 'index',
name: 'Index',
component: Index
},
{
name: 'Wash',
path: 'wash',
component: () => import('../views/Wash.vue')
},
{
name: 'Order',
path: 'order',
component: () => import('../views/Order.vue')
},
{
name: 'My',
path: 'my',
component: () => import('../views/My.vue')
}
]
},
{
name: 'Login',
path: '/login',
component: () => import('../views/Login.vue')
},
{
name: "404",
path: "/:pathMatch(.*)*",
component: () => import('../views/404.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach( ( news,old,next ) => {
next()
})
export default router
8. 配置pinia,并做持久化存儲
npm i?pinia
npm i?pinia-plugin-persist
//在store/index.ts配置pinia和共享數(shù)據(jù)持久化處理
import { createPinia } from "pinia";
import piniaPluginPersist from "pinia-plugin-persist"
const store = createPinia()
store.use(piniaPluginPersist)
export default store
//在mian.ts中引入并掛載pinia
import store from "../src/store/index"
app.use(store)
為了避免共享的數(shù)據(jù)混亂放在一個文件下,因此需模塊化處理不同頁面的共享數(shù)據(jù)
order.ts表示訂單頁面涉及到的共享數(shù)據(jù)及數(shù)據(jù)的處理方法
address.ts表示地址頁面涉及到的共享數(shù)據(jù)及數(shù)據(jù)的處理方法
以order.ts為示例
import { defineStore } from "pinia";
export const orderStore = defineStore( "order", {
//存放需要共享的數(shù)據(jù)
state: () => {
return {
orderType: "takein",
count: 1
}
},
//Store 狀態(tài)的計(jì)算值
getters: {
doubleCount: (state) => state.count * 2
},
//存放同步和異步方法
actions: {
countAdd(num: number){
this.count = this.count + num
}
},
//開啟數(shù)據(jù)持久化存儲
persist: {
enabled: true
}
})
//在頁面使用store中的數(shù)據(jù)
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { orderStore } from '../store/order'; //引入order模塊數(shù)據(jù)
const orderstore = orderStore()
const {count, doubleCount} = storeToRefs(orderstore) //解構(gòu)成響應(yīng)式數(shù)據(jù)
const addNum = (num: number) => {
orderstore.countAdd(num) //用actions中的方法
}
</script>
<template>
<div>state中的數(shù)據(jù)響應(yīng)式展示: {{ count }} </div>
<div>getters中的數(shù)據(jù)響應(yīng)式展示: {{ doubleCount }} </div>
<button @click="addNum(10)">點(diǎn)擊操作state中的數(shù)據(jù)</button>
</template>
<style scoped lang="less">
</style>
?開啟數(shù)據(jù)持久化存儲后,刷新頁面,數(shù)據(jù)不會變成原始數(shù)據(jù)
9. 設(shè)置網(wǎng)站logo和網(wǎng)站名稱
在index.html文件配置網(wǎng)站logo和網(wǎng)站名稱
網(wǎng)站logo的是.ico格式,其他格式圖片需要轉(zhuǎn)成.ico文件
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/tidylogo.ico" /> //配置logo
<title>XXXXX有限公司官方網(wǎng)站</title> //配置網(wǎng)站名稱
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
10. 配置less
? ? ? ? npm i less -D
<style scoped lang="less">
@color: pink; //定義一個顏色變量
//類名嵌套
.title{
div{
color: @color; //使用變量
}
}
</style>
11. 首頁配置自定義tabbar底部欄
//Home.vue中配置tabbar欄數(shù)據(jù)和跳轉(zhuǎn)路由等,同時在router/index.ts中配置相應(yīng)的路由
<script setup lang="ts">
import { ref,reactive,onMounted } from "vue"
onMounted( () => {
})
const active = ref(0)
const tabbarList = reactive([
{
title: '首頁',
path: '/index',
inactive: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/home.png',
active: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/home_active.png'
},
{
title: '洗衣',
path: '/wash',
inactive: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/wash.png',
active: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/wash_active.png'
},
{
title: '訂單',
path: '/order',
inactive: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/order.png',
active: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/order_active.png'
},
{
title: '我的',
path: '/my',
inactive: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/my.png',
active: 'https://tidyimages.oss-cn-hangzhou.aliyuncs.com/newh5/my_active.png'
}
])
const onChangeTab = (index: number | string) => {
console.log(index)
}
</script>
<template>
<router-view></router-view>
<van-tabbar v-model="active" active-color="#26D7CC" route @change="onChangeTab">
<van-tabbar-item replace :to="item.path" v-for="(item,index) in tabbarList" :key="index">
<span :class="active === index ? active : ''">{{ item.title }}</span>
<template #icon="props">
<img :src="props.active ? item.active : item.inactive" />
</template>
</van-tabbar-item>
</van-tabbar>
</template>
<style scoped lang="less">
</style>
效果圖如下:文章來源:http://www.zghlxwxcb.cn/news/detail-655491.html
???????文章來源地址http://www.zghlxwxcb.cn/news/detail-655491.html
到了這里,關(guān)于使用vue3 + TS + Pinia + Vant4 + vite搭建商城H5項(xiàng)目框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!