配置代理
P96 方法一
正文
- 跨域问题
原因
遇到蓝色框的这两东西一般都是跨域报错,原因是违背了同源策略-端口号不同,
请求实际上能正常发给服务器,但是当服务器发给浏览器响应请求时,浏览器发现服务器跨域,所以就没把数据给到我们。
几种解决方式
- 配置cors
只需要后端人员在返回响应时,加几个特殊的响应头即可,但是不好配置-配置后任何人都能找服务器要数据了
- Jsonp
借助<script>标签的src属性在引入外部资源时,不受同源策略限制,但只能解决get请求,需要前后端配合
- 配置代理服务器⭐
如图所示通过一个代理服务器来解决跨域,为什么右边的线能走通呢?因为代理和后端都是服务区,两者通信不需要ajax(前端技术),用到时最原始的http请求,同源策略不适用。
如何配置一个代理服务器
1.使用nginx,但是比较成本高,需要懂后端
2.直接使用Vue-cli配置 官文
//vue.config.js
devServer:{
proxy:'http://localhost:5000' //配置发给哪个服务器
}
//缺点:1.根路径(public)下有配合内容不会走代理 2.不能配置多个代理
others
-
浏览器输入地址敲回车-相当于发送了get()网络请求
-
发送ajax请求-网络请求方式介绍
如上图所示:
1.xhr和fetch是都是js原生的,xhr用起来很麻烦,但是fetch符合Promise风格-更好用quan
2.JQuery和axios都是基于xhr封装的库,JQuery已过时,目前axios比较推荐,采用的也是Promise风格
- 前端服务器根路径
public文件夹相当于本地服务器的根路径-8080里面有内容就看public文件夹下有什么
这里浏览器输入地址get请求能拿到test.txt文件
但axios请求会优先去找根路径下内容,如果有匹配就不会发送给代理服务器了
P97 方法二
code
proxy: {
'/atguigu': { //使用前缀写法-可避免根路径冲突
target: 'http://localhost:5000',// 代理目标的基础路径
pathRewrite:{'^/atguigu':''}, //重写地址-删除前缀 p:如果后端接口已经有前缀了就不需要重写,这里的前缀只是加一个判断
//P:重写路径-用空代替相似atguigu字符、因为后端接收的真正请求路径是不带前缀的
//vue中不写“ws”和“changeOrigin”,默认为true
},
'/demo': { //可以用多个前缀配置多个代理
target: 'http://localhost:5001',
pathRewrite:{'^/demo':''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
}
}
正文
- changeOrigin
可以控制是否对服务器“说谎”,如右图所示值为true时发送配置(假的)的host值
- 文档
- 方法一
vue.config.js配置规则:见上code
说明:
-
优点:配置简单,请求资源时直接发给**前端(8080)**即可。
-
缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
-
工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
-
方法二
vue.config.js配置规则:见上code
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。
github案例
P98 静态组件
other
- 引入bootstrap报错问题
用import './assets/css/bootstrap.css'
这种方式引入检查比较严格,会发现没有bootstrap里面的字体
对于这种第三方css样式库,把文件放在public文件夹下,在main.js中用link引入更合适-检查不容易报错[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Tb7e3Ev-1652603446674)(Images/image-20220206181153948.png)]
<!--main.js-->
<!--引入第三方样式-->
<link rel='stylesheet' href="<%= BASE_URL%>css/bootstrap.css">
P99 列表展示
other
- github提供官方接口
https://api.github.com/search/users?q=xxx
- ``
这个符号专业词汇为模板字符串,里面可以用**${}**来放变量
- github接口为https,而接口代理服务器为http,为什么没有报错跨域呢?
github的工程师用了cros来解决跨域,这个才是真正的解决跨域的方法
P100 完善案例
code
1.List.vue
info:{ //对于能组合的数据可以放在一个对象里,这样方便组件传参
isFirst:true,
isLoading:false,
errMsg:'',
users:[]
}
this.$bus.$on('updateListData',(dataObj)=>{
this.info = {...this.info,...dataObj} //通过解构覆盖的方式-避免属性减少
//this.info = dataObj-这样有问题,如果dataObj只有三个属性,那info属性就不全了
})
2.Search.vue
//this.$bus.$emit('updateListData',isLoading:true,errMsg:'',users:[],isFirst:false)
//P:上面这种不推荐,因为还要保证每个参数顺序正确-麻烦
this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:false})
//使用一个对象传参的方式可以不用考虑参数顺序
axios.get(`xxx`).then(
response => {
this.$bus.$emit('updateListData', {isLoading:false,errMsg:'',users:response.data.items})
},
error => {
this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message})
}
)
P101 vue-resource
正文
- 简介
vue-resource这个是vue插件****,然后也是基于xhr封装的,用法和axios**相同。
不过没怎么维护了,在vue1.0用的比较多,现在不推荐使用
- 如何使用
在main.js中引入插件后,可以看到vm、vc对象上多了一个$http
属性
other
- 怎么使用vue插件-以vueResource为例
1.main.js
//引入插件
import vueResource from 'vue-resource'
//使用插件
Vue.use(vueResource)
2.Search.vue
this.$http.get(`xxx`).then( //用法和axios相同
//P:$http和$bus差不多,猜测是不是所有vue的插件-都赋值在vc、vm中"$xxx"属性
response => {
console.log('请求成功了')
},
error => {
console.log('请求失败了')
}
)
插槽
P102 默认插槽
code
1.Category.vue
<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
2.使用插槽.vue
<Category>
<ul>
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
</Category>
如图
P103 具名插槽
code
1.定义插槽.vue
<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
2.使用插槽.vue
<ul slot="center">
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
old
基本用法
template可以用另一种写法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgXk3GfS-1652603446676)(Images/image-20210818181127590.png)]
P104 作用域插槽(待复看)
如图:
上文中的组件自身-子组件(Category);使用组件-父组件(App)
组件结构:
p:关键点template、scope、:data
Vuex
P105 简介
共享状态
P106 求和案例_纯vue版
见code……
P107 Vuex工作原理
p:为什么要加actions,因为它能做特殊额外的请求处理
P108 搭建Vuex环境
讲解了vuex环境搭建,还有import js文件解析顺序
P:感觉挺重要的,有空补充下笔记
P109 求和案例_vuex版
见code……
P110 Vuex开发者工具的使用
见code……
P111 getters配置项
getters实际上就是store里的computed
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZgWldz1R-1652603446677)(Images/image-20211224155006676.png)]
P112 mapState与mapGetters-
P113 mapActions与mapMutations-
code
1.mapState
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
<!--<h1>当前求和为:{{$store.state.school}}</h1> <!--直接使用vuex属性 -->
<h1>当前求和为:{{sum}}</h1> <!-- 使用计算属性 -->
computed:{
/*sum(){ -自己写计算属性实现
return this.$store.state.sum
}, */
...mapState({sum:'sum'}), //-mapState一般写法-帮我们生成计算属性
...mapState(['sum']), //简写
}
2.mapGetters <!--用法同上-$store.getters -->
...mapGetters({bigSum:'bigSum'})
...mapGetters(['bigSum'])
3.mapMutations
<!--写法差不多,注:模板要传参-$store.dispatch(x)-->
<button @click="increment(n)">
...mapMutations({increment:'JIA'}),
...mapMutations(['JIA']),
4.mapActions
<!--写法同上-$store.commit(x)-->
...mapActions({incrementOdd:'jiaOdd'})
...mapActions(['jiaOdd'])
...mapState
为什么使用...
mapstate输出的实际上是一个对象,所以在computed对象中使用对象需要采用…来解构
正文
- 调试工具输出-
- mapActions和mapMutations-模板 绑定事件 传参
<button @click="increment(n)">+</button>
//生成计算属性需要传value,所以要传参-不传的话increment默认会传event
...mapMutations({increment:'JIA')
/*incrementOdd(value){ 使用mapMutations生成的计算属性键值对实际上是这个
this.$store.commit("JIA",value)
}*/
- 文档
mapXxx方法:用于帮助我们映射Vuex-Xxx
中的数据为计算属性
computed: {
//靠mapXxx生成映射vuex的计算属性
//mapState、mapGetters、mapMutations、mapActions、
...mapXxx({sum:'sum',school:'school',subject:'subject'}), //对象写法
...mapXxx(['sum','school','subject']), //数组简写形式
},
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
other
- 关于对象的 属性简写注意点
mapState({sum:'sum'}),
//不可写成mapState({sum})-因为sum在这里输入的是"sum"字符串,简写会解析成sum变量
P114 多组件共享数据
other
- 唯一id快速生成
import {nanoid} from 'nanoid'
const data={id:nanoid()}
P115 vuex模块化+namespace_1-
P116 vuex模块化+namespace_2-
3:07为啥使用/字符串- 6:30indexof使用 11:00控制台输出 getter写法和state手写不同 -code 14:53代码文件分离 -文档
code
1a.store-count.js
export default {
namespaced:true,//命名空间-实现store模块化,注:必写-使用mapState简写
}
1b.store-person.js
const personAbout = {
namespaced:true,
}
1b.store-index.js
import Vue from 'vue'
import Vuex from 'vuex'
import countOptions from './count'
import personOptions from './person'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
countAbout:countOptions,
personAbout:personOptions
}
})
2.Count.vue
//mapXxx针对模块化vuex的写法
computed:{
...mapState('countAbout',['sum']), //第一个参数是指定命名Store
...mapGetters('countAbout',['bigSum'])
},
methods: {
...mapMutations('countAbout',{increment:'JIA'}),
...mapActions('countAbout',{incrementOdd:'jiaOdd'})
},
3.Person.vue
//基础的store使用写法
computed:{
sum(){
return this.$store.state.countAbout.sum
},
firstPersonName(){
return this.$store.getters['personAbout/firstPersonName']
//与上面的map简写不同,因为mapXxx已自动处理好了
//为什么不能写成getters.personAbout.firstPersonName而要用"/"-因为你不是尤大,人家就喜欢这么设计api
}
},
methods: {
add(){
this.$store.commit('personAbout/ADD_PERSON',personObj)
},
addPersonServer(){
this.$store.dispatch('personAbout/addPersonServer')
}
},
other
- arr.indexOf(x)-返回在数组中可以找到一个给定元素的第一个 索引,如果不存在,则返回**-1**。
路由
P117 路由简介
路由就是一组Key-value的对应关系
多个路由需要路由器就是vue-router
前端(url -component)后端(url-function)
P118 基本使用
vue-router基本用法
P120 嵌套路由
code
1.router.js
{
path:'/home',
component:Home,
children:[
{
path:'news', //嵌套路由
component:News,
},
]
}
2.home.vue
<div>
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<router-view></router-view>
<!-- 嵌套路由组件 -->
</div>
- 注:嵌套路由和嵌套url的区别
old
嵌套路由也叫多级路由
使用语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wZCPduL5-1652603446678)(Images/image-20210816135238832.png)]
注:不要写"/"
P121 路由的query参数
code
<!-- 带query参数to的字符串写法 -->
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">xx</router-link>
<!-- 带query参数to的对象写法 -->
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">
<!-- 上面两种router-link写法:推荐对象洗发-虽然代码长了但是可读性更好,具体选择还得看情况 -->
正文
- 由路由跳转引入的组件叫做组件路由
other
-
开发经常会出现的报错 名词-模板编译失败
-
“``” 的学名-模板字符串
P122 命名路由
code
1.router.js
{
path:'/home',
children:[
{
path:'message',
children:[
{
name:'simpleRoute',
path:'detail',
}
]
}
]
}
2.Message.vue
//<router-link to="/home/message/detail"> //普通写法
<router-link :to="{name:'simpleRoute'}"> //简化写法-感觉也没简化多少hh,可能层级再多点更适用
<router-link :to="{ //简化写法-带query
name:'simpleRoute',
query:{
id:m.id,
}
}">
3.Detail.vue
<li>{{$route.query.id}}</li>
P123 路由的params参数
code
1.router.js
name:'simple',
path:'detail/:id/:title', //params可以写多个-:xx也叫占位符
2.Message.vue
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">xx</router-link>
<router-link :to="{
name:'xiangqing', //注:对象写法的link必须要用name-path报错
params:{
id:m.id,
title:m.title
}
}"/>
3.Detail.vue
<li>{{$route.params.id}}</li>
<li>{{$route.params.title}}</li>
- route对象params控制台输出-
P124 路由的props配置
code
{
name:'xiangqing',
path:'detail',
component:Detail,
props:{a:1,b:'hello'} //对象写法-以props形式传静态key-value给Detail组件
props:true //布尔值写法-所有params
props($route){ //函数写法-传动态对象,参数为$route
return {
id:$route.query.id,//内容自定义
title:$route.params.title,
b:'hello'
}
}
props({query:{id}}){ //解构赋值连续写法-更简洁但语义化不行并不推荐
return {
id,
}
}
}
p125 router-link的replace属性
code
<router-link replace to="/home/news">News</router-link> <!-- 开启replace模式-默认为push -->
正文
- push和raplace模式区别
浏览器左上角箭头可操作路由历史,路由历史的存储是栈-先进先出
1.push 2.replace
P126 编程式路由导航
code
//$router的两个API
this.$router.push({
//name:'xiangqing',
path:'/xxx',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
//name:'xiangqing',
path:'/xxx',
params:{
id:xxx,
title:xxx
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
正文
- 什么叫编程导航-不借助router-link的导航
- 文档
作用:不借助 实现路由跳转,让路由跳转更加灵活
other
- router-link不足-只能及时触发不能延时
P127 缓存路由组件
code
1.Home.vue
<!-- <keep-alive :include="['News','Message']"> --> <!-- 缓存多个 -->
<keep-alive include="News"> //区分标识符为组件名
<router-view></router-view>
</keep-alive>
2.News.vue
name:'News',
正文
- 跳转路由默认前一个页面组件销毁-销毁后返回组件会重新挂载,可以用beforedestroy判断
- 文档
作用:让不展示的路由组件保持挂载,不被销毁。
补充
<!-- 需要缓存的视图组件 -->
<router-view v-if="$route.meta.keepAlive">
</router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive">
</router-view>
P128 两个新的声明周期钩子
正文
- 使用缓存路由组件可能会出现的问题
就是缓存路由组件不能触发beforedestroy,那就无法进行像定时器销毁这样的操作,所以vue有提供专属路由的生命周期替代
//News.vue 缓存路由组件
activated() {
console.log('News组件被激活了')
this.timer = setInterval(() => {},16)
},
deactivated() {
console.log('News组件失活了')
clearInterval(this.timer)
},
-
vue2生命周期图没有出现的三个钩子-activated、deactivated、nextTick
-
文档
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
P129 全局前置_路由守卫-
P130 全局前置_路由守卫-
P131 独享路由守卫-
code
//router.js
routes:[
{
name:'xiaoxi',
path:'message',
component:Message,
//title:'消息'-router只展示含有的配置项
meta:{isAuth:true,title:'消息'}, //meta-路由元信息,可以放一些自定义参数
beforeEnter: (to, from, next) => {……} //独享路由守卫-只有前置
}
]
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next() //只有调用next时路由才跳转
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{ //后置没有next-常用来改变网页名称
if(to.meta.title){
document.title = to.meta.title //修改网页的title-像这种修改还是放后置合适,前置要判断太多
}else{
document.title = 'vue_test'
}
})
P132 组件内路由守卫
code
//About.vue-路由组件
//通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next() //注:加next放行
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
next() //注:加next放行
}
- 组件内守卫和路由守卫的区别
组件内守卫的enter和leave是进入和离开组件的意思,不要和路由守卫的前置后置弄混,感觉只要根据方法名语义来理解即可-且用的不多
P133 history和hash模式
1:00不随http发服务器 2:00#后算hash值 4:23模式配置-code 6:00兼容性8:40serve的本质
10:50打包文件部署 12:00~简单服务器搭建express 14:40前端文件存放在后端的文件名 16:30前端打包文件在后端项目展示 17:30刷新页面请求报错 20:59#后内容不传后端请求资源 22:38使用history不报错解决 和后端合作 23:30后端解决路由冲突 -文档
code
const express =require('express')
const history =require('connect-history-api-fallback')
const app =express()
app.use(history())
app.ues(express.static(__direname+'/static')) //本地资源
app.get('/person',(req,res)=>{
res.send({
name:'tom',
age:18,
})
})
app.listen(5005,err=>{
if(!err) console.log('服务器启动成功')
})
- 后端项目文件结构-
app.ues(express.static(__direname+'/static'))
-可以让浏览器通过发送请求拿到前端文件- 使用histroy后端处理刷新页面报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HgQpGD8S-1652603446680)(Images/image-20220313203451867.png)]
点击前端tab切换路由不走网络请求,但是刷新页面会走网络请求,如果后端没有处理还是history模式,后端就会报错(没有对应路由),但是使用hash就可以解决,因为hash值不会传给后端
- 前端使用history路由模式后端配合解决办法-使用
connect-history-api-fallback
插件
正文
- hash值不随http发送到后端服务器
- 如何配置路由模式
在vueRouter()构造函数中写配置mode:'history'
,默认为hash
-
yarn serve的本质-开启指定端口号内置服务器
-
打包文件必须在服务器上部署才能正常打开-
-
前端文件存放在后端的文件名-static或者public
-
文档
对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
hash模式:
- 地址中永远带着#号,不美观 。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面 服务端404的问题。
Element UI
P134 element-ui基本使用
……
P135 element-ui按需引入
code
1.babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }],
],
plugins:[
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
2.main.js
//按需引入
import { Button} from 'element-ui';
//引入全局组件
Vue.component(Button.name, Button);//Button.name-即是Button别名el-button
3.App.vue
<el-button>默认按钮</el-button>
- element-ui官文的坑
由于官文没有及时 根据vuecli 更新,所以会有很多坑
- .babelrc文件改名为babel.config.js
- -配置改成
"@babel/preset-env"
才能解决
正文
- npm -D的意思-就是开发依赖,禹神说:按需明显是开发需要的,如果生产环境早就打包完了?没懂,不过他说这部分可以看webpack教程
要后端人员支持,解决刷新页面 服务端404的问题。
Element UI
P134 element-ui基本使用
……
P135 element-ui按需引入
code
1.babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }],
],
plugins:[
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
2.main.js
//按需引入
import { Button} from 'element-ui';
//引入全局组件
Vue.component(Button.name, Button);//Button.name-即是Button别名el-button
3.App.vue
<el-button>默认按钮</el-button>
- element-ui官文的坑
由于官文没有及时 根据vuecli 更新,所以会有很多坑
- .babelrc文件改名为babel.config.js
- -配置改成
"@babel/preset-env"
才能解决
正文
- npm -D的意思-就是开发依赖,禹神说:按需明显是开发需要的,如果生产环境早就打包完了?没懂,不过他说这部分可以看webpack教程
xx