Vue2的代理,路由以及通信能手VueX(下)

Vue中的Ajax

4.1Vue中代理和ajax

原理

  • × XHR newHttpRequest() xhr.open() xhr.send() win内置
  • ×jQuery $get $set 80%都是封装DOM操作
  • axios promise风格
  • ×fetch win内置 promise风格(包两层,兼容性有问题)
npm i axios
getData() {
  axios.get("http://localhost:5000/students").then(
    (response) => {
      console.log("请求成功", response.data);
    },
    (error) => {
      console.log("请求失败", error.message);
    }
  );
},

源码理解图

解决跨域

  1. cors(服务器里面写了,携带特殊的响应头)
  2. jsonp 通过script标签的src属性在外部引用资源不受同源限制的策略(只能解决get请求)
  3. 代理服务器(vue-cli,ngnix)
 devServer: {
    proxy: "http://localhost:5000"
 }

上述就是开启一个代理服务器:1、协议http 2、主机localhost 3、端口5000

问题:

  1. 本机服务器中不能和数据服务器同名的文件或者地址
  2. 不能开多个代理
devServer: {
    proxy: {
        '/api':{
            target: "http://localhost:5000",
           	pathRewrite: { '^/api': '' }//这里通过下面原理图解决
            ws: true, // 用于websocket
            changeOrigin: true // 代理服务器是否说谎,控制请求头中host值,true 那么数据服务器检测来源是5000,false,那么数据服务器检测来源是8080
        }
    }
 }

原理

多配置代理

方法一

​ 在vue.config.js中添加如下配置:

devServer:{
  proxy:"http://localhost:5000"
}

说明:

  1. 优点:配置简单,请求资源时直接发给前端(8080)即可。
  2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
  3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

方法二

​ 编写vue.config.js配置具体代理规则:

module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/

说明:

  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
  2. 缺点:配置略微繁琐,请求资源时必须加前缀。

4.2Github搜索案例

asset里面的静态资源是要用ES6的import,会严格检验

解决方法

在public下面建立css,公共引用,用到哪个样式再去看有没有这个样式

<!-- 引入第三方样式 -->
  <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">

List.vue 接受方

<script>
export default {
  name: "List",
  data() {
    return {
      info: {
        isFirst: true,
        isLoad: false,
        errormsg: "",
        users: [],
      },
    };
  },
  mounted() {
    this.$bus.$on("UpdateList", (dataObj) => {
      this.info = { ...this.info, ...dataObj };
    });
  },
};
</script>

search.vue 发送方

<script>
export default {
  name: "Search",
  data() {
    return {
      keyword: "",
    };
  },
  methods: {
    searchName() {
      this.$bus.$emit("UpdateList", {
        isFirst: false,
        isLoad: true,
        errormessage: "",
        users: [],
      });
      axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
        (response) => {
          console.log("请求成功");
          this.$bus.$emit("UpdateList", {
            isLoad: true,
            errormsg: "",
            users: response.data.items,
          });
        },
        (error) => {
          this.$bus.$emit("UpdateList", {
            isLoad: true,
            errormsg: error.message,
            users: [],
          });
        }
      );
    },
  },
};
</script>

4.3vue-resource

npm i vue-resource

一个插件

import vueResource from 'vue-resource'
Vue.user(vueResource)

axios.get(xxx)
this.$http.get(xxx)

4.4solt插槽

默认插槽

App.vue

<template>
  <div class="container">
    <Category title="美食">
      <img src="https://s3.ax1x.com/2021/01/16/srJ1q0.jpg" alt="" />
    </Category>
    <Category title="游戏">
      <u1>
        <li v-for="(g,index)in games" key="index">{{ g }}</li>
      </u1>
    </Category>
    <Category title="电影">
      <video
        controls
        src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
      ></video>
    </Category>
  </div>
</template>

category.vue

<slot>默认</slot>

这里在App里面解析完了才会传给category组件

具名插槽

<Category tit1e="电影">
    <video slot="center"controls src="http://clips.vorwaerts-gmbh.de/big_buck"></video>
<template v-slot:footer>
	<div class="foot">
		<a href=:"http:/nw.atguigu.com">经典</a>
		<a href=:"http:/Mww.atguigu.com">热门k/a>
		<a href=:"http://wMw.atguigu.com">推荐</a>
	</div>
	<h4>欢迎前来观影</h4>
</template>
</Category>
<slot name="foot">默认</slot>

v-slot:name是vue2.6新出的,只能配合template标签使用

作用域插槽

  1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)

  2. 具体编码:

父组件中:
		<Category>
			<template scope="scopeData">
				<!-- 生成的是ul列表 -->
				<ul>
					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category>
			<template slot-scope="scopeData">
				<!-- 生成的是h4标题 -->
				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
			</template>
		</Category>
子组件中:
        <template>
            <div>
                <slot :games="games"></slot>
            </div>
        </template>
		
        <script>
            export default {
                name:'Category',
                props:['title'],
                //数据在子组件自身
                data() {
                    return {
                        games:['lol','dota2','cos','2077']
                    }
                },
            }
        </script>

VueX

5.1概念

**概念:**在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

5.2使用场景

**使用场景:**多个组件需要共享数据时

  1. 多个组件依赖同一状态
  2. 来自不同组件的行为需要变更同一状态

ps:全局事件总线实现数据共享

image-20230622142527942

ps:vuex实现数据共享

image-20230622143431026

5.3纯vue案例

非常简单略

5.4Vuex工作原理

原理图

image-20230623222637962
  1. 这里的state就是存放数据的对象,像之前的toddolist都属于状态或者叫数据
  2. action和mutations都是对象,里面的值是函数,mutations函数有两个参数一个是state,value
  3. ajax需要用到Api
  4. 三个对象都要store管理

5.5搭建Vuex

Vue2对应的vuex是3

npm i vuex@3
  1. 创建文件:src/store/index.js

    //引入Vue核心库
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //应用Vuex插件
    Vue.use(Vuex)
    //准备actions对象——响应组件中用户的动作
    const actions = {
        jia(contex,value){
            context.commit('jia',value)
        }
    }
    //准备mutations对象——修改state中的数据
    const mutations = {
        jia(state,value){
            state.sum+=value
        }
    }
    //准备state对象——保存具体的数据
    const state = {
        sum = 0;
    }
    //创建并暴露store
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state
    })
    
  2. main.js中创建vm时传入store配置项

    ......
    //引入store
    import store from './store'
    ......
    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App),
    	store
    })
    
  3. 初始化数据、配置actions、配置mutations,操作文件store.js

  4. 组件中读取vuex中的数据:$store.state.sum

  5. 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)

    备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

ps:必须在创建store之前use,es6会把import全部提前

5.6Vuex案例

5.7Vuex开发工具

和Vue开发工具同一个

5.8store里的getter

相当于配置了store的计算属性

const getters = {
    bigSum(state) {
        return state.sum * 10
    }
}
{{$store.getters.bigSum}}

5.9mapState/getter

先引入 import {mapState} from ‘vuex’

在computed中使用

对象写法

computed:{
	...mapState({he:'sum',jian:'jian'})
}

数组写法

computed:{
	...mapState(['sum','jian'])
}

5.10mapActs/Mutations

对象写法

<button @click="jia(n)">每次加1</button>
...mapActions({ jia: "jia" }),
...mapMutations({ jia: "JIA" }),

这里默认生成的方法传入的默认值是$event,因此我们需要手动修改传入的参数

数组写法

<button @click="jia(n)">每次加1</button>
...mapActions(['jia']),
...mapMutations(['JIA']),

5.11多组件数据共享

computed:{
	...mapState(['sum','jian'])
}

本质就是通过操作$store中的state从而引入state就可以

5.12Vuex模块化

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const countAbout = {
    namespaced:true,
    actions: {
        jia(context, value) {
            context.commit("JIA", value)
        }
    },
    mutations: {
        JIA(state, value) {
            state.sum += value;
        }
    },
    state: {
        sum: 98
    }
}
export default new Vuex.Store({
    modules: {
        countAbout
    }
})

这里namespaced要true才会被认可s

...mapActions("coutAbout", { jia: "jia" }),
...mapActions("coutAbout", ["jia"]),
 methods: {
    add() {
      const personobj = { id: nanoid(), name: this.name };
      this.$store.commit("personAbout/ADD_PERSON", personobj);
      this.name = "";
    },
  },
 computed:{
     firstP(){
         this.$store.getter["personAbout/firstPersonName"];
     }
 }

这里就需要用路径来解决命名空间问题

Vue-router

6.1介绍和使用

概念

  1. 路由:一组key-value的对应关系
  2. 路由器:多个路由需要经过路由器管理

应用场景

实现SPA应用

  1. 安装vue-router,命令:npm i vue-router@3vue2是用的3,vue3用的4

  2. 应用插件:Vue.use(VueRouter)

  3. 编写router配置项:

    //引入VueRouter
    import VueRouter from 'vue-router'
    //引入Luyou 组件
    import About from '../components/About'
    import Home from '../components/Home'
    
    //创建router实例对象,去管理一组一组的路由规则
    const router = new VueRouter({
    	routes:[
    		{
    			path:'/about',
    			component:About
    		},
    		{
    			path:'/home',
    			component:Home
    		}
    	]
    })
    
    //暴露router
    export default router
    
  4. 实现切换(active-class可配置高亮样式)

    <router-link active-class="active" to="/about">About</router-link>
    
  5. 指定展示位置

    <router-view></router-view>
    

几个注意点

  1. pages放路由组件
  2. 路由组件是频繁挂载和销毁的
  3. 每个组件都有$route,存放自己路由信息
  4. 只有一个$router
const router = new VueRouter({
	routes:[
		{
			path:'/about',
			component:About,
            children:[
                {
                    path:'news',
                    component:News
                }
            ]
		},
		{
			path:'/home',
			component:Home
		}
	]
})

6.2路由传参

简单示例

  1. 传递参数

    <router-link :to="·/home/message/detail?id=${msg.id}&title=${msg.title}·">跳转</router-link>				
    <router-link 
    	:to="{
    		path:'/home/message/detail',
    		query:{
    		   id:666,
                title:'你好'
    		}
    	}"
    >跳转</router-link>
    
  2. 接收参数:

    $route.query.id
    $route.query.title
    

6.3路由命名

可以把使用路由的时候替换path

:to={name:‘about’}

6.4路由的params参数

直接示例

  1. 配置路由,声明接收params参数

    {
    	path:'/home',
    	component:Home,
    	children:[
    		{
    			path:'news',
    			component:News
    		},
    		{
    			component:Message,
    			children:[
    				{
    					name:'xiangqing',
    					path:'detail/:id/:title', //使用占位符声明接收params参数
    					component:Detail
    				}
    			]
    		}
    	]
    }
    
  2. 传递参数

    <!-- 跳转并携带params参数,to的字符串写法 -->
    <router-link :to="/home/message/detail/666/你好">跳转</router-link>
    				
    <!-- 跳转并携带params参数,to的对象写法 -->
    <router-link 
    	:to="{
    		name:'xiangqing',
    		params:{
    		   id:666,
                title:'你好'
    		}
    	}"
    >跳转</router-link>
    

    特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

6.5路由的props配置

​ 作用:让路由组件更方便的收到参数

{
	name:'xiangqing',
	path:'detail/:id',
	component:Detail,

	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
	// props:{a:900}

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}

6.6router-link的replace

浏览器的历史记录(栈)push模式

replace模式就是破坏push模式

<router-link replace :to="·/home/message/detail?id=${msg.id}&title=${msg.title}·">跳转</router-link>				

6.7编程式路由导航

作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵活

method:{
	pushShow(m){
		this.$router.push({
			name: '详情',
            path: '/home/message/detail'
			query:{
				id:m.id,
				title:m.title
			}
		})
	},
	replaveShow(m){
		this.$router.replace({
			name: '详情',
			query:{
				id:m.id,
				title:m.title
			}
		})
	}
}

回退,前进

methods: {
    back() {
      this.$router.back();
    },
    forward() {
       this.$router.forward();
    },
  },

6.8缓存路由组件

实际上我们切换组件的时候会销毁组件,缓存哪个路由组件

  1. 作用:让不展示的路由组件保持挂载,不被销毁。

  2. 具体编码:

    <keep-alive include="News"> 
        <router-view></router-view>
    </keep-alive>
    
    <keep-alive :include=["News","Messages"]> 
        <router-view></router-view>
    </keep-alive>
    

6.9新的生命周期钩子

场景:

  • 缓存组件的里面使用了定时器,不触发销毁了
  • 两个新的钩子是路由组件独有的
  1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  2. 具体名字:
    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。

6.10路由守卫

  • 都是在src/router/index.js里面进行配置
  • 前置路由过滤之后有的标题要改
  • 独享是每个route里面的配置项
  1. 作用:对路由进行权限控制

  2. 分类:全局守卫、独享守卫、组件内守卫

  3. 全局守卫:

    //全局前置守卫:初始化时执行、每次路由切换前执行
    router.beforeEach((to,from,next)=>{
    	console.log('beforeEach',to,from)
    	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
    		if(localStorage.getItem('name') === 'yovvis'){ //权限控制的具体规则
    			next() //放行
    		}else{
    			alert('暂无权限查看')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next() //放行
    	}
    })
    
    //全局后置守卫:初始化时执行、每次路由切换后执行
    router.afterEach((to,from)=>{
    	console.log('afterEach',to,from)
    	if(to.meta.title){ 
    		document.title = to.meta.title //修改网页的title
    	}else{
    		document.title = 'vue_test'
    	}
    })
    
  4. 独享守卫:

    beforeEnter(to,from,next){
    	console.log('beforeEnter',to,from)
    	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
    		if(localStorage.getItem('school') === 'atguigu'){
    			next()
    		}else{
    			alert('暂无权限查看')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next()
    	}
    }
    
  5. 组件内守卫:

    //进入守卫:通过路由规则,进入该组件时被调用
    beforeRouteEnter (to, from, next) {
    },
    //离开守卫:通过路由规则,离开该组件时被调用
    beforeRouteLeave (to, from, next) {
    }
    

***ps:***组件内守卫的离开是要切换另一个组件的时候调用,而不是像全局路由守卫点击组件前后都调用

6.11路由器工作模式

mode:'history'
  1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

  2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

  3. hash模式:

    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:

    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。(每次刷新都会找服务器要资源)

简单创建一个本地服务器

node+express

UI组件库

```js
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}
```

***ps:***组件内守卫的离开是要切换另一个组件的时候调用,而不是像全局路由守卫点击组件前后都调用

6.11路由器工作模式

mode:'history'
  1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

  2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

  3. hash模式:

    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:

    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。(每次刷新都会找服务器要资源)

简单创建一个本地服务器

node+express

UI组件库

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yovvis

buy me a coffee

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

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

打赏作者

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

抵扣说明:

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

余额充值