【前端Vue】Vue3+Pinia小兔鲜电商项目第6篇:整体认识和路由配置,本资源由 收集整理【附代码文档】

Vue3+ElementPlus+Pinia开发小兔鲜电商项目完整教程(附代码资料)主要内容讲述:认识Vue3,使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行时机,2. setup中写代码的特点。什么是pinia,创建空Vue项目并安装Pinia1. 安装elementPlus和自动导入插件,2. 配置自动按需导入,3. 测试组件,1. 安装sass,2. 准备定制化的样式文件,3. 自动导入配置。静态结构搭建和分类实现,banner轮播图实现1. 整体结构创建,2. 分类实现,1. 熟悉组件,2. 获取数据渲染组件,1. 纯静态结构,2. 完整代码。静态结构搭建和路由配置,面包屑导航渲染1. 准备分类组件,2. 配置路由,3. 配置导航区域链接,1. 认识组件准备模版,2. 封装接口,3. 渲染面包屑导航。整体认识和路由配置,渲染基础数据1. 准备组件模版,2. 配置路由,3. 绑定模版测试跳转,1. 封装接口,2. 获取数据渲染模版,1. 渲染基础热榜数据。整体认识和路由配置,表单校验实现1. 准备模版,2. 配置路由跳转,1. 校验要求,2. 代码实现。本地购物车,接口购物车1. 添加购物车,2. 头部购物车,3. 列表购物车-基础内容渲染,4. 列表购物车-单选功能实现,5. 列表购物车-全选功能实现,6. 列表购物车-统计数据功能实现。路由配置和基础数据渲染,切换地址-打开弹框交互1. 准备组件模版,2. 配置路由,3. 封装接口,4. 渲染数据,1. 准备弹框模版,2. 控制弹框打开。![image.png](,基础数据渲染1. 准备接口,2. 获取数据渲染内容,1. 支付携带参数,2. 沙箱账号信息,1. 准备模版,2. 绑定路由。Sku组件封装1. 准备模版渲染规格数据,2. 选中和取消选中实现,3. 规格禁用功能实现,4. 产出Prop数据。

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

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


全套教程部分目录:


部分文件图片:

本资源由 收集整理

整体认识和路由配置

1. 准备模版

<script setup>

</script>


<template>
  <div>
    <header class="login-header">
      <div class="container m-top-20">
        <h1 class="logo">
          <RouterLink to="/">小兔鲜</RouterLink>
        </h1>
        <RouterLink class="entry" to="/">
          进入网站首页
          <i class="iconfont icon-angle-right"></i>
          <i class="iconfont icon-angle-right"></i>
        </RouterLink>
      </div>
    </header>
    <section class="login-section">
      <div class="wrapper">
        <nav>
          <a href="javascript:;">账户登录</a>
        </nav>
        <div class="account-box">
          <div class="form">
            <el-form label-position="right" label-width="60px"
              status-icon>
              <el-form-item  label="账户">
                <el-input/>
              </el-form-item>
              <el-form-item label="密码">
                <el-input/>
              </el-form-item>
              <el-form-item label-width="22px">
                <el-checkbox  size="large">
                  我已同意隐私条款和服务条款
                </el-checkbox>
              </el-form-item>
              <el-button size="large" class="subBtn">点击登录</el-button>
            </el-form>
          </div>
        </div>
      </div>
    </section>

    <footer class="login-footer">
      <div class="container">
        <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 &copy; 小兔鲜儿</p>
      </div>
    </footer>
  </div>
</template>

<style scoped lang='scss'>
.login-header {
  background: #fff;
  border-bottom: 1px solid #e4e4e4;

  .container {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
  }

  .logo {
    width: 200px;

    a {
      display: block;
      height: 132px;
      width: 100%;
      text-indent: -9999px;
      background: url("@/assets/images/logo.png") no-repeat center 18px / contain;
    }
  }

  .sub {
    flex: 1;
    font-size: 24px;
    font-weight: normal;
    margin-bottom: 38px;
    margin-left: 20px;
    color: #666;
  }

  .entry {
    width: 120px;
    margin-bottom: 38px;
    font-size: 16px;

    i {
      font-size: 14px;
      color: $xtxColor;
      letter-spacing: -5px;
    }
  }
}

.login-section {
  background: url('@/assets/images/login-bg.png') no-repeat center / cover;
  height: 488px;
  position: relative;

  .wrapper {
    width: 380px;
    background: #fff;
    position: absolute;
    left: 50%;
    top: 54px;
    transform: translate3d(100px, 0, 0);
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);

    nav {
      font-size: 14px;
      height: 55px;
      margin-bottom: 20px;
      border-bottom: 1px solid #f5f5f5;
      display: flex;
      padding: 0 40px;
      text-align: right;
      align-items: center;

      a {
        flex: 1;
        line-height: 1;
        display: inline-block;
        font-size: 18px;
        position: relative;
        text-align: center;
      }
    }
  }
}

.login-footer {
  padding: 30px 0 50px;
  background: #fff;

  p {
    text-align: center;
    color: #999;
    padding-top: 20px;

    a {
      line-height: 1;
      padding: 0 10px;
      color: #999;
      display: inline-block;

      ~a {
        border-left: 1px solid #ccc;
      }
    }
  }
}

.account-box {
  .toggle {
    padding: 15px 40px;
    text-align: right;

    a {
      color: $xtxColor;

      i {
        font-size: 14px;
      }
    }
  }

  .form {
    padding: 0 20px 20px 20px;

    &-item {
      margin-bottom: 28px;

      .input {
        position: relative;
        height: 36px;

        >i {
          width: 34px;
          height: 34px;
          background: #cfcdcd;
          color: #fff;
          position: absolute;
          left: 1px;
          top: 1px;
          text-align: center;
          line-height: 34px;
          font-size: 18px;
        }

        input {
          padding-left: 44px;
          border: 1px solid #cfcdcd;
          height: 36px;
          line-height: 36px;
          width: 100%;

          &.error {
            border-color: $priceColor;
          }

          &.active,
          &:focus {
            border-color: $xtxColor;
          }
        }

        .code {
          position: absolute;
          right: 1px;
          top: 1px;
          text-align: center;
          line-height: 34px;
          font-size: 14px;
          background: #f5f5f5;
          color: #666;
          width: 90px;
          height: 34px;
          cursor: pointer;
        }
      }

      >.error {
        position: absolute;
        font-size: 12px;
        line-height: 28px;
        color: $priceColor;

        i {
          font-size: 14px;
          margin-right: 2px;
        }
      }
    }

    .agree {
      a {
        color: #069;
      }
    }

    .btn {
      display: block;
      width: 100%;
      height: 40px;
      color: #fff;
      text-align: center;
      line-height: 40px;
      background: $xtxColor;

      &.disabled {
        background: #cfcdcd;
      }
    }
  }

  .action {
    padding: 20px 40px;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .url {
      a {
        color: #999;
        margin-left: 10px;
      }
    }
  }
}

.subBtn {
  background: $xtxColor;
  width: 100%;
  color: #fff;
}
</style>

2. 配置路由跳转

 <li><a href="javascript:;" @click="router.push('/login')">请先登录</a></li>

表单校验实现

1. 校验要求

用户名:不能为空,字段名为 account 密码:不能为空且为6-14个字符,字段名为 password 同意协议:必选,字段名为 agree

2. 代码实现

<script setup>
import { ref } from 'vue'
// 表单数据对象
const userInfo = ref({
  account: '1311111111',
  password: '123456',
  agree: true
})

// 规则数据对象
const rules = {
  account: [
    { required: true, message: '用户名不能为空' }
  ],
  password: [
    { required: true, message: '密码不能为空' },
    { min: 6, max: 24, message: '密码长度要求6-14个字符' }
  ],
  agree: [
    {
      validator: (rule, val, callback) => {
        return val ? callback() : new Error('请先同意协议')
      }
    }
  ]
}


</script>


<template>
    <div class="form">
      <el-form ref="formRef" :model="userInfo" :rules="rules" status-icon>
        <el-form-item prop="account" label="账户">
          <el-input v-model="userInfo.account" />
        </el-form-item>
        <el-form-item prop="password" label="密码">
          <el-input v-model="userInfo.password" />
        </el-form-item>
        <el-form-item prop="agree" label-width="22px">
          <el-checkbox v-model="userInfo.agree" size="large">
            我已同意隐私条款和服务条款
          </el-checkbox>
        </el-form-item>
        <el-button size="large" class="subBtn" >点击登录</el-button>
      </el-form>
    </div>
</template>

登录基础业务实现

基础思想 1. 调用登录接口获取用户信息 2. 提示用户当前是否成功 3. 跳转到首页

import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'


const doLogin = () => {
  const { account, password } = form.value
  // 调用实例方法
  formRef.value.validate(async (valid) => {
    // valid: 所有表单都通过校验  才为true
    console.log(valid)
    // 以valid做为判断条件 如果通过校验才执行登录逻辑
    if (valid) {
      // TODO LOGIN
      await loginAPI({ account, password })
      // 1. 提示用户
      ElMessage({ type: 'success', message: '登录成功' })
      // 2. 跳转首页
      router.replace({ path: '/' })
    }
  })
}

Pinia管理用户数据

基本思想:Pinia负责用户数据相关的state和action,组件中只负责触发action函数并传递参数

// 管理用户数据相关

import { defineStore } from 'pinia'
import { ref } from 'vue'
import { loginAPI } from '@/apis/user'

export const useUserStore = defineStore('user', () => {
  // 1. 定义管理用户数据的state
  const userInfo = ref({})
  // 2. 定义获取接口数据的action函数
  const getUserInfo = async ({ account, password }) => {
    const res = await loginAPI({ account, password })
    userInfo.value = res.result
  }
  // 3. 以对象的格式把state和action return
  return {
    getUserInfo
  }
}, {
  persist: true,
})

请求拦截器携带token

基础思想:很多接口如果想要获取数据必须要带着有效的Token信息才可以,拦截器中做一次,用到axios实例的其他都可以拿到

// axios请求拦截器
httpInstance.interceptors.request.use(config => {
  // 1. 从pinia获取token数据
  const userStore = useUserStore()
  // 2. 按照后端的要求拼接token数据
  const token = userStore.userInfo.token
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
}, e => Promise.reject(e))

退出登录实现

基础思想: 1. 清除用户信息 2. 跳转到登录页

1- 新增清除用户信息action

 // 退出时清除用户信息
  const clearUserInfo = () => {
    userInfo.value = {}
  }

2- 组件中执行业务逻辑

<script setup>
import { useUserStore } from '@/stores/userStore'
import { useRouter } from 'vue-router'
const userStore = useUserStore()
const router = useRouter()
const confirm = () => {
  console.log('用户要退出登录了')
  // 退出登录业务逻辑实现
  // 1.清除用户信息 触发action
  userStore.clearUserInfo()
  // 2.跳转到登录页
  router.push('/login')
}
</script>

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/564825.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习-17】数据变换---小波变换特征提取及应用案列介绍

引言 在机器学习领域&#xff0c;数据变换是一种常见且重要的预处理步骤。通过对原始数据进行变换&#xff0c;我们可以提取出更有意义的特征&#xff0c;提高模型的性能。在众多数据变换方法中&#xff0c;小波变换是一种非常有效的方法&#xff0c;尤其适用于处理非平稳信号和…

实战解析:SpringBoot接口防抖机制与防重复提交技巧

目录 前言 啥是防抖 思路解析 哪一类接口需要防抖? 如何确定接口是重复的&#xff1f; 分布式部署下如何做接口防抖&#xff1f; 使用共享缓存 使用分布式锁 Spring Boot与Redis深度整合入口&#xff1a;实战指南 具体实现 请求锁 唯一key生成 重复提交判断 Red…

scipy.sparse.csr_matrix 中的 indptr indices data

# ------------------------------------------------------------------------------- # Description: 分析理解 scipy.sparse.csr_matrix 中的 indptr & indices & data # Reference: https://blog.csdn.net/bymaymay/article/details/81389722 # Author: Sophia…

Win 进入桌面黑屏,只有鼠标

大家好&#xff0c;我叫秋意零。 今天&#xff0c;遇到一个同事电脑进入桌面黑屏&#xff0c;只有鼠标。经过询问沟通&#xff0c;说是 Windows 突然进行了自动更新&#xff0c;更新之后桌面就黑了屏。经过查询是一个桌面进程没启动才会导致桌面黑屏。首先分两种情况&#xff0…

STL Array、ForwardList源码剖析

STL Array、ForwardList源码剖析 参考文章: https://blog.csdn.net/weixin_45389639/article/details/121618243 array 源代码 template<typename _Tp,std::size_t _Nm> struct array {typedef _Tp value_type;typedef _Tp* pointer;typedef value_type* iterator;// Su…

【看不懂命令行、.yaml?】Hydra 库极速入门

Hydra 是一个开源的 Python 框架&#xff0c;可以简化研究和其他复杂应用程序的开发。其核心功能是通过组合动态创建层次化的配置&#xff0c;并可以通过配置文件和命令行进行覆盖。Hydra 的名字来源于它能够运行多个类似的作业 - 就像一个多头的水怪一样。 主要特性: 从多个…

首发!Llama3纯本地部署攻略!中文方法!

引言 llama3在4月19日刚刚发布&#xff0c;官方的对比结果中在开源模型中堪称世界第一&#xff0c;整好周六日有时间&#xff0c;在魔搭社区上测试一下 一、启动环境 登录魔搭社区&#xff0c;到自己的机器资源&#xff0c;可以看到&#xff0c;可选的机器配置&#xff0c; …

YOLOv9改进策略 | Conv篇 | 利用 Haar 小波的下采样HWD替换传统下采样(改变YOLO传统的Conv下采样)

一、本文介绍 本文给大家带来的改进机制是Haar 小波的下采样HWD替换传统下采样&#xff08;改变YOLO传统的Conv下采样&#xff09;在小波变换中&#xff0c;Haar小波作为一种基本的小波函数&#xff0c;用于将图像数据分解为多个层次的近似和细节信息&#xff0c;这是一种多分…

什么是自动化测试?如何做自动化测试?

前面介绍了功能测试和接口测试&#xff0c;在介绍接口测试时提到了实现API自动化。那具体什么是自动化&#xff0c;为什么要做自动化&#xff0c;这里我们集中总结。 一. 什么是自动化&#xff1f; 顾名思义&#xff0c;自动化测试是相对人工测试而言的&#xff0c;它是指把人…

以太网帧格式解析

以太网的正式标准是IEEE802.3&#xff0c;它规定了以太网传输的帧结构。 以太网帧格式如下图所示&#xff1a; 以太网传输数据时&#xff0c;是按照上图的格式&#xff0c;自左到右依次传输的。需要注意的是前导码和SFD不属于以太网协议的内容&#xff0c;应该是属于物理层数据…

AI检索增强生成引擎-RAGFlow-深度理解知识文档,提取真知灼见

&#x1f4a1; RAGFlow 是什么&#xff1f; RAGFlow是一款基于深度文档理解构建的开源RAG&#xff08;Retrieval-Augmented Generation&#xff09;引擎。RAGFlow个人可以为各种规模的企业及提供一套专业的RAG工作流程&#xff0c;结合针对用户群体的大语言模型&#xff08;LL…

我独自升级崛起怎么下载 一文分享我独自升级崛起游戏下载教程

我独自升级崛起怎么下载 一文分享我独自升级崛起游戏下载教程 我独自升级&#xff1a;崛起是一款由韩国漫画改编而成的热门多人网络在线联机游戏&#xff0c;这款游戏是一款的角色扮演类型游戏&#xff0c;游戏有着独一无二的剧情模式。小伙伴们在游戏中可以体验到独特的成长系…

Meta提出全新文档级嵌入框架,利用LLM来增强信息检索能力

近年来&#xff0c;基于嵌入式检索&#xff08;embedding-based search&#xff09;或密集检索&#xff08;dense retrieval&#xff09;相比传统的稀疏检索&#xff08;sparse retrieval&#xff09;或基于词袋&#xff08;bag of words&#xff09;的方法&#xff0c;已经展示…

王道C语言督学营OJ课后习题(课时20)

#include<stdio.h> int main() {printf("%3d%3d",0,13);return 0; }

图深度学习——2.图的理论知识

1.图 1.1 图的定义 图是由节点&#xff08;顶点&#xff09;和边构成的数学结构。图用于表示对象之间的关系&#xff0c;其中节点表示对象&#xff0c;边表示对象之间的关系。 一个图&#xff0c;记为 G <V, E> &#xff0c;它包括以下两个要素&#xff1a; 1.节点&am…

函数的内容

一&#xff0c;概念 封装一份可以被重复执行的代码块&#xff0c;让大量代码重复使用 二&#xff0c;函数使用 大体分两步&#xff1a;声明函数&#xff0c;调用函数 声明函数有关键字&#xff1a;function 函数名&#xff08;&#xff09;{ 函数体 } 为基本格式&#xf…

linux系统安全与应用【下】

目录 1.开关机安全控制 1.1GRUB限制 2.终端登录安全控制 2.1 限制root只在安全终端登录 2.2 禁止普通用户登录 3.弱口令检测 3.1 Joth the Ripper&#xff08;JR&#xff09; 4.网络端口扫描 4.1 nmap命令 1.开关机安全控制 1.1GRUB限制 通常情况下在系统开机进入GRU…

哈希表实现[很详细!]

目录 哈希表 定义节点类 根据hash码获取value 向hash表存入新key value,如果key重复,则更新value 根据hash码删除,返回删除的value 关于resize()一些问题的解答 冲突测试 MurmurHash 设计思考 练习 Leetcode01 Leetcode03 Leetcode49 Leetcode217 Leetcode136 L…

人工智能大模型培训老师叶梓 探索知识库问答中的查询图生成:处理多跳复杂问题的新方法

在人工智能领域&#xff0c;基于知识库的问答&#xff08;KBQA&#xff09;技术正变得越来越重要。它使得机器能够理解自然语言问题&#xff0c;并从结构化的知识库中检索答案。然而&#xff0c;面对多跳复杂问题&#xff0c;传统的KBQA方法往往力不从心。近期&#xff0c;研究…

账号安全基本措施1

一、系统账号清理 1.1 将用户设置为无法登录 useradd -s /sbin/nologin lisi shell类型设置为/sbin/nologin用户将无法使用bash或其他shell来登录系统。 1.2 锁定用户。passwd -l 用户名 正常情况下是可以送普通用户切换到其他普通用户的 当锁定密码后passwd -l lisi就用普…