【前端Vue】Vue3+Pinia小兔鲜电商项目第2篇:什么是pinia,1. 创建空Vue项目【附代码文档】

本文主要是介绍【前端Vue】Vue3+Pinia小兔鲜电商项目第2篇:什么是pinia,1. 创建空Vue项目【附代码文档】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


全套教程部分目录:


部分文件图片:

什么是pinia

Pinia 是 Vue 的专属状态管理库,可以实现跨组件或页面共享状态,是 vuex 状态管理工具的替代品,和 Vuex相比,具备以下优势

  1. 提供更加简单的API (去掉了 mutation )
  2. 提供符合组合式API风格的API (和 Vue3 新语法统一)
  3. 去掉了modules的概念,每一个store都是一个独立的模块
  4. 搭配 TypeScript 一起使用提供可靠的类型推断

创建空Vue项目并安装Pinia

1. 创建空Vue项目

npm init vue@latest

2. 安装Pinia并注册

npm i pinia

import { createPinia } from 'pinia'const app = createApp(App)
// 以插件的形式注册
app.use(createPinia())
app.use(router)
app.mount('#app')

实现counter

核心步骤:

  1. 定义store
  2. 组件使用store

1- 定义store

import { defineStore } from 'pinia'
import { ref } from 'vue'export const useCounterStore = defineStore('counter', ()=>{// 数据 (state)const count = ref(0)// 修改数据的方法 (action)const increment = ()=>{count.value++}// 以对象形式返回return {count,increment}
})

2- 组件使用store

<script setup>// 1. 导入use方法import { useCounterStore } from '@/stores/counter'// 2. 执行方法得到store store里有数据和方法const counterStore = useCounterStore()
</script><template><button @click="counterStore.increment">{{ counterStore.count }}</button>
</template>

实现getters

getters直接使用计算属性即可实现

// 数据(state)
const count = ref(0)
// getter (computed)
const doubleCount = computed(() => count.value * 2)

异步action

思想:action函数既支持同步也支持异步,和在组件中发送网络请求写法保持一致
步骤:

  1. store中定义action
  2. 组件中触发action

1- store中定义action

const API_URL = 'export const useCounterStore = defineStore('counter', ()=>{// 数据const list = ref([])// 异步actionconst loadList = async ()=>{const res = await axios.get(API_URL)list.value = res.data.data.channels}return {list,loadList}
})

2- 组件中调用action

<script setup>import { useCounterStore } from '@/stores/counter'const counterStore = useCounterStore()// 调用异步actioncounterStore.loadList()
</script><template><ul><li v-for="item in counterStore.list" :key="item.id">{{ item.name }}</li></ul>
</template>

storeToRefs保持响应式解构

直接基于store进行解构赋值,响应式数据(state和getter)会丢失响应式特性,使用storeToRefs辅助保持响应式

<script setup>import { storeToRefs } from 'pinia'import { useCounterStore } from '@/stores/counter'const counterStore = useCounterStore()// 使用它storeToRefs包裹之后解构保持响应式const { count } = storeToRefs(counterStore)const { increment } = counterStore</script><template><button @click="increment">{{ count }}</button>
</template>

创建项目并整理目录

npm init vue@latest

![image.png](

jsconfig.json配置别名路径

配置别名路径可以在写代码时联想提示路径

{"compilerOptions" : {"baseUrl" : "./","paths" : {"@/*":["src/*"]}}
}

elementPlus引入

1. 安装elementPlus和自动导入插件

npm i elementPlus
npm install -D unplugin-vue-components unplugin-auto-import

2. 配置自动按需导入

// 引入插件
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({plugins: [// 配置插件AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),]
})

3. 测试组件

<template><el-button type="primary">i am button</el-button>
</template>

定制elementPlus主题

1. 安装sass

基于vite的项目默认不支持css预处理器,需要开发者单独安装

npm i sass -D

2. 准备定制化的样式文件

/* 只需要重写你需要的即可 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with ($colors: ('primary': (// 主色'base': #27ba9b,),'success': (// 成功色'base': #1dc779,),'warning': (// 警告色'base': #ffb302,),'danger': (// 危险色'base': #e26237,),'error': (// 错误色'base': #cf4444,),)
)

3. 自动导入配置

这里自动导入需要深入到elementPlus的组件中,按照官方的配置文档来

  1. 自动导入定制化样式文件进行样式覆盖
  2. 按需定制主题配置 (需要安装 unplugin-element-plus)
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 导入对应包
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),// 按需定制主题配置ElementPlus({useSource: true,}),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}},css: {preprocessorOptions: {scss: {// 自动导入定制化样式文件进行样式覆盖additionalData: `@use "@/styles/element/index.scss" as *;`,}}}
})

axios安装并简单封装

1. 安装axios

npm i axios

2. 基础配置

官方文档地址:[
基础配置通常包括:

  1. 实例化 - baseURL + timeout
  2. 拦截器 - 携带token 401拦截等
import axios from 'axios'// 创建axios实例
const http = axios.create({baseURL: 'timeout: 5000
})// axios请求拦截器
instance.interceptors.request.use(config => {return config
}, e => Promise.reject(e))// axios响应式拦截器
instance.interceptors.response.use(res => res.data, e => {return Promise.reject(e)
})export default http

3. 封装请求函数并测试

import http from '@/utils/http'export function getCategoryAPI () {return http({url: 'home/category/head'})
}

路由整体设计

路由设计原则:找页面的切换方式,如果是整体切换,则为一级路由,如果是在一级路由的内部进行的内容切换,则为二级路由

<template>我是登录页
</template>
<template>我是首页
</template>
<template>我是home
</template>
<template>我是分类
</template>
// createRouter:创建router实例对象
// createWebHistory:创建history模式的路由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'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),// path和component对应关系的位置routes: [{path: '/',component: Layout,children: [{path: '',component: Home},{path: 'category',component: Category}]},{path: '/login',component: Login}]
})export default router

静态资源引入和Error Lens安装

1. 静态资源引入

  1. 图片资源 - 把 images 文件夹放到 assets 目录下
  2. 样式资源 - 把 common.scss 文件放到 styles 目录下

2. Error Lens插件安装

![image.png](

scss变量自动导入

$xtxColor: #27ba9b;
$helpColor: #e26237;
$sucColor: #1dc779;
$warnColor: #ffb302;
$priceColor: #cf4444;
css: {preprocessorOptions: {scss: {// 自动导入scss文件additionalData: `@use "@/styles/element/index.scss" as *;@use "@/styles/var.scss" as *;`,}}
}

组件结构快速搭建

<script setup></script><template><nav class="app-topnav"><div class="container"><ul><template v-if="true"><li><a href="javascript:;""><i class="iconfont icon-user"></i>周杰伦</a></li><li><el-popconfirm title="确认退出吗?" confirm-button-text="确认" cancel-button-text="取消"><template #reference><a href="javascript:;">退出登录</a></template></el-popconfirm></li><li><a href="javascript:;">我的订单</a></li><li><a href="javascript:;">会员中心</a></li></template><template v-else><li><a href="javascript:;">请先登录</a></li><li><a href="javascript:;">帮助中心</a></li><li><a href="javascript:;">关于我们</a></li></template></ul></div></nav>
</template><style scoped lang="scss">
.app-topnav {background: #333;ul {display: flex;height: 53px;justify-content: flex-end;align-items: center;li {a {padding: 0 15px;color: #cdcdcd;line-height: 1;display: inline-block;i {font-size: 14px;margin-right: 2px;}&:hover {color: $xtxColor;}}~li {a {border-left: 2px solid #666;}}}}
}
</style>
<script setup></script><template><header class='app-header'><div class="container"><h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1><ul class="app-header-nav"><li class="home"><RouterLink to="/">首页</RouterLink></li><li> <RouterLink to="/">居家</RouterLink> </li><li> <RouterLink to="/">美食</RouterLink> </li><li> <RouterLink to="/">服饰</RouterLink> </li></ul><div class="search"><i class="iconfont icon-search"></i><input type="text" placeholder="搜一搜"></div><!-- 头部购物车 --></div></header>
</template><style scoped lang='scss'>
.app-header {background: #fff;.container {display: flex;align-items: center;}.logo {width: 200px;a {display: block;height: 132px;width: 100%;text-indent: -9999px;background: url('@/assets/images/logo.png') no-repeat center 18px / contain;}}.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;}}}.search {width: 170px;height: 32px;position: relative;border-bottom: 1px solid #e7e7e7;line-height: 32px;.icon-search {font-size: 18px;margin-left: 5px;}input {width: 140px;padding-left: 5px;color: #666;}}.cart {width: 50px;.curr {height: 32px;line-height: 32px;text-align: center;position: relative;display: block;.icon-cart {font-size: 22px;}em {font-style: normal;position: absolute;right: 0;top: 0;padding: 1px 6px;line-height: 1;background: $helpColor;color: #fff;font-size: 12px;border-radius: 10px;font-family: Arial;}}}
}
</style>
<template><footer class="app_footer"><!-- 联系我们 --><div class="contact"><div class="container"><dl><dt>客户服务</dt><dd><i class="iconfont icon-kefu"></i> 在线客服</dd><dd><i class="iconfont icon-question"></i> 问题反馈</dd></dl><dl><dt>关注我们</dt><dd><i class="iconfont icon-weixin"></i> 公众号</dd><dd><i class="iconfont icon-weibo"></i> 微博</dd></dl><dl><dt>下载APP</dt><dd class="qrcode"><img src="images/41474d5f-a7c8-40c2-b60c-14bbbfa30f13-1710675035.jpg" /></dd><dd class="download"><span>扫描二维码</span><span>立马下载APP</span><a href="javascript:;">下载页面</a></dd></dl><dl><dt>服务热线</dt><dd class="hotline">400-0000-000 <small>周一至周日 8:00-18:00</small></dd></dl></div></div><!-- 其它 --><div class="extra"><div class="container"><div class="slogan"><a href="javascript:;"><i class="iconfont icon-footer01"></i><span>价格亲民</span></a><a href="javascript:;"><i class="iconfont icon-footer02"></i><span>物流快捷</span></a><a href="javascript:;"><i class="iconfont icon-footer03"></i><span>品质新鲜</span></a></div><!-- 版权信息 --><div class="copyright"><p><a href="javascript:;">关于我们</a><a href="javascript:;">帮助中心</a><a href="javascript:;">售后服务</a><a href="javascript:;">配送与验收</a><a href="javascript:;">商务合作</a><a href="javascript:;">搜索推荐</a><a href="javascript:;">友情链接</a></p><p>CopyRight © 小兔鲜儿</p></div></div></div></footer>
</template><style scoped lang='scss'>
.app_footer {overflow: hidden;background-color: #f5f5f5;padding-top: 20px;.contact {background: #fff;.container {padding: 60px 0 40px 25px;display: flex;}dl {height: 190px;text-align: center;padding: 0 72px;border-right: 1px solid #f2f2f2;color: #999;&:first-child {padding-left: 0;}&:last-child {border-right: none;padding-right: 0;}}dt {line-height: 1;font-size: 18px;}dd {margin: 36px 12px 0 0;float: left;width: 92px;height: 92px;padding-top: 10px;border: 1px solid #ededed;.iconfont {font-size: 36px;display: block;color: #666;}&:hover {.iconfont {color: $xtxColor;}}&:last-child {margin-right: 0;}}.qrcode {width: 92px;height: 92px;padding: 7px;border: 1px solid #ededed;}.download {padding-top: 5px;font-size: 14px;width: auto;height: auto;border: none;span {display: block;}a {display: block;line-height: 1;padding: 10px 25px;margin-top: 5px;color: #fff;border-radius: 2px;background-color: $xtxColor;}}.hotline {padding-top: 20px;font-size: 22px;color: #666;width: auto;height: auto;border: none;small {display: block;font-size: 15px;color: #999;}}}.extra {background-color: #333;}.slogan {height: 178px;line-height: 58px;padding: 60px 100px;border-bottom: 1px solid #434343;display: flex;justify-content: space-between;a {height: 58px;line-height: 58px;color: #fff;font-size: 28px;i {font-size: 50px;vertical-align: middle;margin-right: 10px;font-weight: 100;}span {vertical-align: middle;text-shadow: 0 0 1px #333;}}}.copyright {height: 170px;padding-top: 40px;text-align: center;color: #999;font-size: 15px;p {line-height: 1;margin-bottom: 20px;}a {color: #999;line-height: 1;padding: 0 10px;border-right: 1px solid #999;&:last-child {border-right: none;}}}
}
</style>
<script setup>
import LayoutNav from './components/LayoutNav.vue'
import LayoutHeader from './components/LayoutHeader.vue'
import LayoutFooter from './components/LayoutFooter.vue'
</script><template><LayoutNav /><LayoutHeader /><RouterView /><LayoutFooter />
</template>

字体图标渲染

字体图标采用的是阿里的字体图标库,样式文件已经准备好,在 index.html文件中引入即可

  <link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">

一级导航渲染

![image.png](
实现步骤

  1. 封装接口函数
  2. 调用接口函数
  3. v-for渲染模版

代码落地


import httpInstance from '@/utils/http'export function getCategoryAPI () {return httpInstance({url: '/home/category/head'})
}
<script setup>import { getCategoryAPI } from '@/apis/layout'import { onMounted, ref } from 'vue'const categoryList = ref([])const getCategory = async () => {const res = await getCategoryAPI()categoryList.value = res.result}onMounted(() => getCategory())</script><template><header class='app-header'><div class="container"><h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1><ul class="app-header-nav"><li class="home" v-for="item in categoryList" :key="item.id"><RouterLink to="/">{{ item.name }}</RouterLink></li></ul><div class="search"><i class="iconfont icon-search"></i><input type="text" placeholder="搜一搜"></div><!-- 头部购物车 --></div></header>
</template>

吸顶导航交互实现

1. 准备组件静态结构

<script setup></script><template><div class="app-header-sticky"><div class="container"><RouterLink class="logo" to="/" /><!-- 导航区域 --><ul class="app-header-nav "><li class="home"><RouterLink to="/">首页</RouterLink></li><li><RouterLink to="/">居家</RouterLink></li><li><RouterLink to="/">美食</RouterLink></li><li><RouterLink to="/">服饰</RouterLink></li><li><RouterLink to="/">母婴</RouterLink></li><li><RouterLink to="/">个护</RouterLink></li><li><RouterLink to="/">严选</RouterLink></li><li><RouterLink to="/">数码</RouterLink></li><li><RouterLink to="/">运动</RouterLink></li><li><RouterLink to="/">杂项</RouterLink></li></ul><div class="right"><RouterLink to="/">品牌</RouterLink><RouterLink to="/">专题</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;// 此处为关键样式!!!// 状态一:往上平移自身高度 + 完全透明transform: translateY(-100%);opacity: 0;// 状态二:移除平移 + 完全不透明&.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>

2. 渲染基础数据

3. 实现吸顶交互

核心逻辑:根据滚动距离判断当前show类名是否显示,大于78显示,小于78,不显示

<script setup>
import LayoutHeaderUl from './LayoutHeaderUl.vue'
// vueUse
import { useScroll } from '@vueuse/core'
const { y } = useScroll(window)
</script><template><div class="app-header-sticky" :class="{ show: y > 78 }"><!-- 省略部分代码 --></div>
</template>

Pinia优化重复请求

import { ref } from 'vue'
import { defineStore } from 'pinia'
import { getCategoryAPI } from '@/apis/layout'
export const useCategoryStore = defineStore('category', () => {// 导航列表的数据管理// state 导航列表数据const categoryList = ref([])// action 获取导航数据的方法const getCategory = async () => {const res = await getCategoryAPI()categoryList.value = res.result}return {categoryList,getCategory}
})

未完待续, 同学们请等待下一期

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

这篇关于【前端Vue】Vue3+Pinia小兔鲜电商项目第2篇:什么是pinia,1. 创建空Vue项目【附代码文档】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/836119

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多