Vue2_尚品汇前端项目day02超详细笔记_尚硅谷

1:编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误?

--路由跳转有两种形式:声明式导航编程式导航

--声明式导航没有这类问题的,因为vue-router底层已经处理好了

(通俗来说,多点击两次搜索会警告错误)(该警告对于程序没有任何影响)

1.1 为什么编程式导航进行路由跳转的时候,就有这种警告错误?

"vue-router":"^3.5.3":最新的vue-router引入promise

function push(){

rerurn new Promise((resolve,reject)=>{

})

}

比如有个push函数,返回Promise,Promise需要传入成功与失败回调,没传会警告

1.2 通过给push方法传递相应的成功、失败的回调函数,可以捕获到当前错误,可以解决。( 加上 ()=>{},()=>{} )

1.3 通过底部的代码,可以实现解决错误

this.$router.push({name:"search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},()=>{},()=>{});

这种写法:治标不治本,将来在别的组件当中push | replace,编程式导航还有类似错误。

1.4

this:当前组件实例(search)

this.$router属性:当前的这个属性,属性值VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加$router| $route属性

pushVueRouter类的一个实例

如:

function VueRouter(){

}

//原型对象的方法

VueRouter.prototype.push=function(){

//函数的上下文为VueRouter类的一个实例

}

let $router = new VueRouter();

$router.push(xxx);

console.log(this);

console.log(this.$router);

call | | apply区别

相同点:都可以调用函数一次,都可以纂改函数的上下文一次

不同点:call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组

!!!编程式导航进行路由跳转的 “治本” 方法:

//先把VueRouter原型对象的push,先保存一份     //router文件夹->index.js
let originPush = VueRouter.prototype.push;

//重写push|replace
//第一个参数:告诉原来push方法,你往哪里跳转(传递哪些参数)
//第二个参数:成功的回调
//第三个参数:失败的回调
VueRouter.prototype.push=function(location,resolve,reject){
    if(resolve && reject){   //成功与失败的回调都传了
        //this是VueRouter实例,originPush.call(this)调用的还是VueRouter实例
        originPush.call(this,location,resolve,reject);//(originPush()是错误的,调用的上下文是Windows)
    }else{
        //否则,手动传入两个回调函数
        originPush.call(this,location,()=>{},()=>{});
    }
}

重写replace与push方法类似(只需将其中的push改为replace)。

2:Home模块组件拆分

--先把静态页面完成

--拆分出静态组件

--获取服务器的数据进行展示

--动态业务

3:三级联动组件完成

---由于三级联动,在Home、Search、Detail,把三级联动注册为全局组件。

好处只需要注册一次,就可以在项目任意地方使用

<script>    <!-- Home文件夹--TypeNav文件夹--index.vue文件 -->
export default {
  name: "TypeNav",
};
</script>
import Vue from 'vue'    //main.js文件
import App from './App.vue'
//三级联动组件--全局组件
import TypeNav from '@/pages/Home/TypeNav';    //@是src别名
//第一个参数:全局组件的名字 第二个参数:哪一个组件
Vue.component(TypeNav.name,TypeNav)//TypeNav.name可以获取到名字 name: "TypeNav"
<template>
  <div>
 <!-- main.js:三级联动全局组件:三级联动已经注册为全局组件,因此不需要引入(可直接使用) -->
      <TypeNav/>
  </div>
</template>

4:完成其余静态组件

HTML + CSS + 图片资源 ---信息【结构、样式、图片资源】

如:商品分类ListContainer

(index.vue文件编写其template和style)

<script>    <!-- Home文件夹下的index.vue -->
//引入其余的组件(不是全局组件)
import ListContainer from '@/pages/Home/ListContainer';

export default {
  name:'',
  components:{
    //注册
    ListContainer 
  }
}
</script>

(其余组件,如今日推荐Recommend,商品排行Rank,猜你喜欢Like,商标Brand,底层Floor类似以上实现步骤)

5:POSTMAN测试接口

--刚刚经过postman工具测试,接口是没有问题的

--如果服务器返回的数据code字段200,代表服务器返回数据成功

--整个项目,接口前缀都有/api字样

6:axios二次封装

XMLHttpRequest、fetch、JQ、axios 都是用来向服务器端发送请求,并获得响应

安装axios

报错1

cnpm : 无法加载文件 C:\Users\abc\AppData\Roaming\npm\cnpm.ps1,因

为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft

.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。

所在位置 行:1 字符: 1

+ cnpm install --save axios

+ ~~~~

+ CategoryInfo : SecurityError: (:) [],PSSecurityExc

eption

+ FullyQualifiedErrorId : UnauthorizedAccess

解决办法

从命令提示符(CMD)打开PowerShell

1、单击任务栏上的搜索按钮,输入CMD,启动命令提示符,然后输入:start powershell

2、输入“ set-ExecutionPolicy RemoteSigned”回车

3、根据提示,输入A,回车

(输入get-ExecutionPolicy验证是否成功,此时系统回复Restricted,表示状态是禁止的)

报错2

set-ExecutionPolicy : 对注册表项“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Mi

crosoft.PowerShell”的访问被拒绝。 要更改默认(LocalMachine)作用域的执行策略,请使用“以管理员身

份运行”选项启动 Windows PowerShell。要更改当前用户的执行策略,请运行 "Set-ExecutionPolicy -Scop

e CurrentUser"。

所在位置 行:1 字符: 1

+ set-ExecutionPolicy RemoteSigned

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : PermissionDenied: (:) [Set-ExecutionPolicy], UnauthorizedAccessEx

ception

+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.

SetExecutionPolicyCommand

解决方法

1、在Windows PowerShell中执行命令:Set-ExecutionPolicy -Scope CurrentUser

2、接着提示我们输入执行策略(ExecutionPolicy),我们把此策略RemoteSigned输入进去

3、根据提示,输入A,回车

4、输入get-ExecutionPolicy来验证是否成功,若系统回复Restricted,表示状态是禁止的,反之是成功的,如图

5、再次在VS code的终端terminal中输入cnpm install --save axios命令,安装axios成功

6、同时可在package.json文件可以查看axios是否安装成功

6.1 为什么需要进行二次封装axios?

请求拦截器、响应拦截器:

请求拦截器可以在发请求之前可以处理一些业务

响应拦截器当服务器数据返回以后,可以处理一些事情

6.2 在项目当中经常API文件夹【axios】

接口当中:路径都带有/api

baseURL:"/api"

(作用:在发请求的路径http://xxx.xxx:8080后面自动带上/api,就不用自己书写/api了,默认变为:http://xxx.xxx:8080/api

6.3 有的同学axios基础不会,可以参考git|npm 关于axios文档

对于axios进行二次封装 步骤

src文件夹-->api文件夹-->request.js文件

//先安装axios
//对于axios进行二次封装    
//引入axios
import axios from 'axios';

//1:利用axios对象的方法create,去创建一个axios实例
//2:request就是axios,只不过稍微配置一下
const requests = axios.create({
    //配置对象
    //基础路径,发请求的时候,路径当中会出现api
    baseURL:"/api",
    //代表请求超时的时间5s
    timeout:5000,

});
//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出之前做一些事情
requests.interceptors.request.use((config)=>{
    //config:配置对象,对象里面有一个属性很重要,headers请求头
    return config;
});

//响应拦截器
requests.interceptors.response.use((res)=>{
    //成功的回调函数,服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
    return res.data;
}),(error=>{
    //响应失败的回调函数
    return Promise.reject(new Error('false'));//(终止Promise)
});


//(将axios对象requests)对外暴露
export default requests;

src文件夹-->api文件夹-->index.js文件

//当前这个模块:API接口进行统一管理    
import requests  from "./request";

//三级联动的接口
///api/product/getBaseCategoryList  get请求 无参数
 //发请求:axios发请求返回结果Promise对象

/*
 export const reqCategoryList = ()=> {
    return requests({url:'/product/getBaseCategoryList',method:'get'})
 };
可以简化:去掉{},去掉return
 */

export const reqCategoryList = ()=> requests({
            url:'/product/getBaseCategoryList',
                                            method:'get'});//baseURL已经带上api

入口文件main.js进行测试

//测试
import {reqCategoryList} from '@/api';//分别暴露reqCategoryList,需要带 {}
reqCategoryList();

结果是该请求将出现404错误(跨域问题)

7:接口统一管理

项目很小(如:两个组件,接口1-2个):完全可以在组件的生命周期函数中发请求

项目大(如:数百组件,接口数十个):axios.get('xxx')

7.1 跨域问题

什么是跨域 :协议、域名、端口号不同请求,称之为跨域

http://localhost:8080/#/home ---前端项目本地服务器

http://gmall-h5-api.atguigu.cn ---后台服务器

跨域解决方案:JSONP、CROS、代理

解决跨域

vue.config.js文件中->代理跨域

module.exports = {
  //关闭eslint
  lintOnSave:false,
  //代理跨域
  devServer:{
    proxy:{
      '/api':{//'/api'(可以其它路径):若路径带有/api,则进行转发
        target:' http://gmall-h5-api.atguigu.cn',//获取数据的ip地址
       // pathRewrite:{'^/api':''},路径重写(本项目路径中需要有/api,不用重写)
      },
    },
  },
}

配置vue.config.js(配置文件)需要重新启动(npm run serve),但Edge浏览器无法查看该跨域问题是否解决,需用谷歌浏览器查看

Edge浏览器:

谷歌浏览器:

报错(可忽略)

Refused to apply style from 'http://localhost:8080/iconfont.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

解决

CSS文件中有个import引入,将其删除即可

8:nprogress进度条的使用

start进度条开始nProgress.start();

done进度条结束nProgress.done();

进度条颜色可以修改的,当然需要修改人家的样式。

进度条使用步骤

src文件夹->api文件夹->request.js文件

//引入进度条
import nProgress from 'nprogress';
//引入进度条的样式
import 'nprogress/nprogress.css';

请求拦截器代码中添加 nProgress.start();

    //进度条开始动
    nProgress.start();

响应拦截器代码中添加 nProgress.done();

 //进度条结束
    nProgress.done();

安装nprogress

同时可在package.json文件可以查看nprogress是否安装成功

修改nprogress进度条颜色

9:vuex状态管理库

9.1 vuex是什么?

vuex是官方提供的一个插件,状态管理库,集中式管理项目中组件共用的数据。

切记,并不是全部项目都需要Vuex,如果项目很小,完全不需要Vuex,如果项目很大,组件很多、数据很多,数据维护很费劲,则可使用Vuex

Vuex的几大核心概念

state:仓库存储数据的地方

mutations修改state唯一手段

action:处理action,可以书写自己的业务逻辑,也可以处理异步

getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便

9.2 Vuex基本使用

(src文件夹下新建store文件夹)

mapStatemapGetters是映射在计算属性里面的,

mapActionsmapMutations是映射在methods里面的)

state中的数据,组件中如何获取?------- this.$store.state.xxx属性

store.js中的getters,组件中如何获取?--------this.$store.getters.xxxx(getters名称)

安装vuex

报错

peerDependencies WARNING vuex@latest requires a peer of vue@^3.2.0 but vue@2.7.14 was installed

解决

在vuex后添加@3(指定版本为3)

例子(帮助理解)(可忽略)

Home文件夹下的index.vue(可忽略)

<template>
  <div>
      <button @click="add">点击我加上1</button>
      <span>仓库的数据{{count}}</span>
      <button>点击我减去1</button>
  </div>
</template>

<script>
import {mapState} from 'vuex';//引入mapState辅助函数

export default {
  name:'',
  computed:{
    ...mapState(['count']), // 等同于下面的这种方式,ES6 ... 扩展运算符(对象展开符)
        // count: function () {
        //     return this.$store.state.count
        // }
  },
  methods:{
    add(){
      //派发action
      this.$store.dispatch('add');//dispatch调用的是actions里的add方法,commit调用的是mutations里的add方法
    }
  }
}
</script>

知识点

...mapState(['count']), // 等同于下面的这种方式,ES6 ... 扩展运算符(对象展开符)

// count: function () {

// return this.$store.state.count

// }

//dispatch调用的是actions里的add方法,commit调用的是mutations里的add方法

store文件夹下的index.js(可忽略)

import Vue from 'vue';
import Vuex from 'vuex';//使用vuex前需先引入
//需要使用插件一次
Vue.use(Vuex);
//state:仓库存储数据的地方
const state = {
    count:1
};
//mutations:修改state的唯一手段
const mutations = {
    ADD(state){
        state.count++;
    }
};
//action:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {
    //这里可以书写业务逻辑,但是不能修改state
    add({commit}){
        commit("ADD");
    }
};
//getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {};

//对外暴露Store类的一个实例
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters,

});

main.js文件(可忽略)

//引入仓库
import store from '@/store';
new Vue({
  render: h => h(App),
 ...
  //注册仓库:组件实例的身上会多一个书写$store属性
  store
  ...
}).$mount('#app')

9.3 vuex实现模块化开发

如果项目过大,组件过多,接口也很多,数据也很多,可以让vuex实现模块式开发

步骤

创建store文件夹->Search文件夹->index.js文件(Home文件夹同样)

//search模块的小仓库
const state = {};
const mutations = {};
const actions = {};
const getters = {};
export default{//上面写完仍是常量(对象),需对外暴露别的模块才能使用
    state,
    mutations,
    actions,
    getters
}

store文件夹->index.js

import Vue from 'vue';
import Vuex from 'vuex';//使用vuex前需先引入
//需要使用插件一次
Vue.use(Vuex);

//引入小仓库
import home from './home';
import search from './search';

//对外暴露Store类的一个实例
export default new Vuex.Store({
    //实现Vuex仓库模块式开发存储数据
    modules:{
        home,
        search,
    }
});

TypeNav文件夹->index.vue文件

import { mapState } from "vuex";
export default {
  name: "TypeNav",
  //组件挂载完毕,可以向服务器发请求
  mounted() {
    //通知Vuex发请求,获取数据,存储于仓库当中
    this.$store.dispatch("categoryList");
  },
  computed: {
    ...mapState({
      //对象写法:右侧需要的是一个函数,当使用这个计算属性的时候,右侧函数会立即执行一次
      //注入一个参数state,其实即为大仓库的数据
      /* categoryList:(state)=>{
        return state.home.categoryList;
      }  只有一个参数可去除(),可简化为以下形式*/
      categoryList: (state) => state.home.categoryList,
    }),
  },
};
</script>

store文件夹->home文件夹->index.js文件

import { reqCategoryList } from "@/api";
//home模块的小仓库
const state = {
    //state中的数据(data)默认初始值别瞎写,服务器返回对象,起始值则为对象。
//【根据接口返回值确定】
    categoryList:[],
}
const mutations = {
    CATEGORYLIST(state, categoryList) {
        state.categoryList = categoryList;
    }
};
const actions = {
    //通过API里面的接口函数调用,向服务器发请求,获取服务器的数据
    async categoryList({ commit }) {
        let result = await reqCategoryList();//await与async需同时存在
                                        //(计算结果是 Promise 对象或者其它值)
        if (result.code = 200) {
            commit("CATEGORYLIST", result.data);
        }
    }
};
const getters = {};
export default {
    state,
    mutations,
    actions,
    getters
}

快捷键

Ctrl + h 全局替换

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pomelo-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值