尚硅谷 VUE 尚品汇项目实战问题解决方式整理(Vue3 版)

教学视频:https://www.bilibili.com/video/BV1Vf4y1T7bw

  1. 不回要资料的评论,资料在视频底下评论有些仓库里面有。
  2. 试图自行解决问题也是程序员必备技能之一,多做尝试多查资料。

目前进度:EP109

前言

这篇文章中我会把一些实战过程中遇到的问题以及自己的想法记录下来,并且附上我自己的解决方式。因为想练习 Vue3,所以我并没有跟着老师选 Vue2,以下所有内容都是 Vue 3

工具版本:

  • @vue/cli 5.0.4
  • Vue 3.2.13
  • vue-router 4
  • node.js 16.13.1
  • vuex 4.0.2
  • swiper 8.1.4 -> 轮播图
  • vue-lazyload -> vue3-lazyload 0.3.2 -> 懒加载
  • vee-validate 4.5.11 -> 表单验证

代码并非 100% 与老师写的相同,如果我觉得不合理或不合逻辑处会自行修正。本人编程程度不精,若有任何代码有隐患或错误之处欢迎在评论一起交流。

P 1

须先自行全局安装 nodejs 及 vue-cli。

  1. nodejs 需自官网下载及安装 https://nodejs.org/en/

  2. nodejs 安装后再打开 cmd 输入指令安装 vue-cli:npm install -g @vue/cli

P 2

Vue 片段扩展可以使用: Vue 3 Snippets,直接在编辑器输入 vue init 就能自动初始化 .vue 文件内容。

在这里插入图片描述

14: 03 没有 package-lock.json 这个文件

有弹幕问说自己为什么没有 package-lock.json 这个文件,这是因为 package-lock.json 是你在安装过项目依赖之后才会出现的缓存性文件,如果本来没有这个文件的话,跑一个 npm i 安装一下项目依赖它就会出现了。

在没有 package-lock.json 的时候安装项目依赖会比较慢,一旦安装产生 package-lock.json 缓存文件后,下次安装依赖就会快很多。

P 3

02:43 --open 会错误

--open 前加上 --host 192.168.1.26 这里的 192.168.1.26 请改成你的本地 IP。

可以用 cmd 输入 ipconfig 找到你使用的网路 IPv4 位址。

在这里插入图片描述
在这里插入图片描述

P 5

如果安装 less-loader@5 报错,可以直接安装最新版,npm install less less-loader --save-dev 没任何问题。

14: 28

引入 reset.css 这段 rel="icon" 改成 stylesheet

<link rel="stylesheet" href="./reset.css">

然后 reset.css 中有用到 iconfont.css,所以也要一并放到 public 文件夹底下。

P 6

05:00 为什么都命名为 index.vue

弹幕有人提到为什么都用 index.vue,这不是很容易搞混?为什么不跟着组件名称一起取呢?

个人见解是如果使用 index.vue 会更好识别是这个组件的主文件,并且使用 index 作为名称的话在引入的时候可以省略不写,比如说我要在 App.vue 中引入 Header,我直接 import Header from "./components/Header" 就可以,不需要写全 import Header from "./components/Header/index.vue"

如果有人知道原因,也可以评论告诉我一下~

10:24 路由配置

Vue 3 + Vue router 4 的使用方法如下:

修改 /src/router/index.js 为:

// 配置路由
import {
    createRouter, createWebHistory } from "vue-router";

// 引入路由組件
import Home from "@/pages/Home";
import Login from "@/pages/Login";
import Register from "@/pages/Register";
import Search from "@/pages/Search";

const routes = [
  {
   
    path: "/home",
    name: "Home",
    component: Home,
  },
  {
   
    path: "/login",
    name: "Login",
    component: Login,
  },
  {
   
    path: "/register",
    name: "Register",
    component: Register,
  },
  {
   
    path: "/search",
    name: "Search",
    component: Search,
  },
];

const router = createRouter({
   
  history: createWebHistory(),
  routes,
});

export default router;

修改 main.js

import {
    createApp } from "vue";
import App from "./App.vue";

// 引入路由
import router from "@/router";

const app = createApp(App);
app.use(router);
app.mount("#app");

App.vue 的 Header 跟 Footer 之间加上 <rotuer-view /> 用于显示路由组件内容:

<template>
  <div>
    <Header />
      <router-view />
    <Footer />
  </div>
</template>

15:55

老师这里查看 $route 的工具是 chrome 的扩展 Vue.js devtools,装上之后 Ctrl + Shift + I 打开开发人员工具,会有一个 Vue 标签。

在这里插入图片描述
18:09

path 直接写 * 会报错 Catch all routes ("*") must now be defined using a param with a custom regexp.,因为 Vue3 对 404 配置进行了修改,必须要使用正则匹配。

解决方式是匹配所有路径,使用 /:pathMatch(.*)/:catchAll(.*) 代替 *

P 9

04:09 path 不能结合 params 参数使用

这部分老师提到 path 不能结合 params 参数使用,实际上是可以跳转,但是无法接收到 params 参数,并且控制台会有警告:

[Vue Router warn]: Path "Search" was passed with params but they will be ignored.
Use a named route alongside params instead.
router.push({
   
       path: "/search", // 改为 name
       params: {
   
         keyword: data.keyword,
       },
       query: {
   
         k: data.keyword.toUpperCase(),
       },
});

就是建议你将 path 改为 name 不然 params 参数会被忽略。

14:22 params 传空字串

面试第三题,如果 params 传空字串过去,params 参数占位符后面有加问号就没事,如果没有加就会报错 Missing required param "keyword"

其实这边有点不太明白老师说的,因为如果占位符后面有加问号的话,不管传什么或者不传都不会有问题。

P 10

这一集老师提到 VueRouter 的部分并不适用于 vue-router 4,大概听一下理解就好。

06:01

个人测试 vue-router 4 多次传递相同的 params 参数过去并不会在控制台报错,但如果将 push 的结果以 result 储存然后打印出来,会发现其实第二次开始的 PromiseResult 都会有出现 Error,但实际使用过程中不会有任何影响。

"Avoided redundant navigation to current location: "/search/test?k=TEST"."

在这里插入图片描述
用成功及失败回调函数一样无法解决这个问题,不过对使用没影响也不会跳出 error 所以就不管它了。

14:58 VueRouter 这部分讲的太绕了

个人认为老师这部分讲解的有点绕,我自己的理解如下:

  1. VueRouter 是一个
  2. push 是 VueRouter 原型上的一个方法
  3. $router 为 VueRouter 类的实例
  4. 因此 $router 可以通过原型链找到 VueRouter 身上的方法
  5. VueRouter 身上的方法有 push,所以可以用 $router.push 来呼叫 push 这个方法。
// VueRouter 类
function VueRouter() {
   
	// ...
}

// push 是 VueRouter 原型上的一个方法
VueRouter.prototype.push = function(){
   
	// 函数的上下文为 VueRouter 类的一个实例
}

// $router 为 VueRouter 类的实例
let $router = new VueRouter(); 

// 通过原型链找到 VueRouter 身上的 push 方法
$rotuer.push(xxx);

this.$router.push();

补充

这部分内容是参考 Vue Router 官方文档 做的一些修正。

在 vue-router 4 之后,VueRouter 不再是一个类,而是一组函数。所以改写 replace 跟 push 这部分不能再这样做了。

// previously was
// import Router from 'vue-router'
import {
    createRouter } from 'vue-router'

const router = createRouter({
   
  // ...
})

之前是 VueRouter 类的原型中可以找到 push 跟 replace 方法,现在则是在 createRouter 的实例中找到。

import {
    createRouter, createWebHistory } from "vue-router";

const router = createRouter({
   
  history: createWebHistory(),
  routes,
});

console.log(router);
/*
...
push: f push(to)
replace: f replace(to)
*/

在这里插入图片描述
所以应该要这样改写:

const router = createRouter({
   
  history: createWebHistory(),
  routes,
});

// 先把 router 的 push, replace 方法保存
let originPush = router.push;
let originReplace = router.replace;

// 重写 push | replace
router.push = function (location, resolve, reject) {
   
  if (resolve && reject) {
   
    originPush.call(this, location, resolve, reject);
  } else {
   
    originPush.call(
      this,
      location
    );
  }
};

router.replace = function (location, resolve, reject) {
   
  if (resolve && reject) {
   
    originReplace.call(this, location, resolve, reject);
  } else {
   
    originReplace.call(
      this,
      location,
      () => {
   },
      () => {
   }
    );
  }
};

不过 vue-router 4 应该是不用重写 push 跟 replace 了,毕竟没有遇到相同的情况,所以这边我选择跳过。

P 12

06:24 Vue 3注册全局组件

Vue 2.x 可以通过 Vue.component() 来注册全局组件,但 Vue 3.0 开始需要先透过 Vue.createApp() 建立一个实例后再注册全局组件,写法如下:

import {
    createApp } from "vue";
import App from "./App.vue";

// 使用 createApp 建立一个实例
const app = createApp(App);

import router from "@/router";
app.use(router);

// 注册全局组件
import TypeNav from "@/pages/Home/TypeNav";
app.component(TypeNav.name, TypeNav);

app.mount("#app");

P 16

09:22 API 404

老师这边估计是著急想讲跨域知识点所以没注意到其实404是因为 baseURL 写错了,最新的接口 baseURL 应该写成 baseURL: "http://gmall-h5-api.atguigu.cn/api"

而且跨域问题后端已经处理好,所以前端其实不用做任何处理。

P 18

11:57 vuex 4.0

vuex 4.0 之后的使用方式和老师演示的不一样,写法为:

store/index.js

import {
    createStore } from "vuex";

// state: 仓库存储数据的地方
const state = {
   };
// mutations: 修改 state 的唯一手段
const mutations = {
   };
// action: 处理 action, 可以书写自己的业务逻辑, 也可以处理异步
const actions = {
   };
// getters: 理解为计算属性, 用于简化仓库数据, 让组件获取仓库的数据更为方便
const getters = {
   };

export const store = createStore({
   
  state,
  mutations,
  actions,
  getters,
});

而 Vue 3.0 开始不再提供功能的全域注册,而是注册在根组件实例上,所以我们需要在 main.js 加上以下代码:

// 引入仓库
import {
    store } from "@/store";
// 注册仓库: 组件实例的身上会多一个 $store 属性
app.use(store);

P 19

18:39 多出运动健康

完成三级联动菜单部分时最后一个 运动健康 可能会跑版,修改一下 h3 样式中的 line-height 就行:

.all-sort-list2 {
   
        .item {
   
          h3 {
   
            line-height: 27px;
            /* ... */
          }
        }
}

虽然不应该直接写死…但资料给的 CSS 都是写死的 px,之后有空再改吧。

或者也可以直接把 运动健康 给删掉,就是把最后一个 pop 掉就行。

P 25

08:50 节流

我目前使用的 lodash 版本为 4.17.21,现在不能使用 import { throttle } from "lodash/throttle"; 来引入节流 API,而是要改成 import { throttle } from "lodash"; 才可以。

另外如果想要自己写节流的话,下面是我的写法,可以参考一下:

const data = reactive({
   
  // ...
  throttleTimer: false,
});

// 节流
const throttle = (callback, time) => {
   
  if (data.throttleTimer) return;
  data.throttleTimer = true;

  setTimeout(() => {
   
    callback();
    data.throttleTimer = false;
  }, time);
  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值