Ajax库-axios
安装axios:npm i axios
请求发出后,报错:请求跨域
解决方式
解决方式1:使用代理服务器:在vue.config.js中添加如下配置
```html
devServer:{
proxy:"http://ip:端口"
}
```
代码示例
- vue.config.js添加后台服务路径
module.exports={ devServer:{ proxy:'http://localhost:9006' } }
- 组件
<template>
<div id="app">
<input type="search" v-model="key"/>
<button @click="getStudentInfo">获取学生信息</button>
<hr/>
<table>
<tr>
<td>ID</td>
<td>学生账号</td>
<td>学生姓名</td>
<td>学生年龄</td>
<td>学生性别</td>
<td>所属老师</td>
</tr>
<tr v-for="(student,index) in studentList" :key="student.id">
<td>{{student.id}}</td>
<td>{{student.stuCode}}</td>
<td>{{student.stuName}}</td>
<td>{{student.stuAge}}</td>
<td>{{student.stuGender}}</td>
<td>{{student.teName}}</td>
</tr>
</table>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'app',
components: {
},
data(){
return{
studentList:[],
key: ''
}
},
methods:{
getStudentInfo(){
// axios.get('http://localhost:8080/student/getStudentInfo').then(
axios.post(`http://localhost:8080/school/student/getStudentInfo?key=${this.key}`).then(
response=>{
console.log("请求成功!",response.data)
this.studentList = response.data
},
error=>{
console.log("请求失败",error.message)
}
)
},
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
table{
margin: auto;
border: 1px solid black;
border-spacing: 0;
}
td{
width: 80px;
border: 1px solid black;
}
tr{
height: 50px;
}
</style>
优点
- 配置简单,请求资源时直接发给前端(8080)即可。
缺点
- 不能配置多个代理,不能灵活的控制请求是否走代理。
工作方式
- 若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
解决方式2:编写vue.config.js配置具体代理规则
- 编写vue.config.js配置具体代理规则
proxy: { '/api1': {// 匹配所有以 '/api1'开头的请求路径 target: 'http://localhost:9006',// 代理目标的基础路径 changeOrigin: true,// 用于控制请求头中的host值 pathRewrite: {'^/api1': ''} }
- changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
- changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
- changeOrigin默认值为true
优点
- 可以配置多个代理,且可以灵活的控制请求是否走代理
缺点
- 配置略微繁琐,请求资源时必须加前缀
代码示例
vue.config.js添加后台服务路径
module.exports = {
devServer: {
proxy: {
'/school': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:9006',// 代理目标的基础路径
changeOrigin: true,// 用于控制请求头中的host值
//匹配所有以school开头的请求路径,将school替换为空字符串
//可以将下面一行注释掉看看效果
pathRewrite: {'^/school': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:9007',// 代理目标的基础路径
changeOrigin: true,// 用于控制请求头中的host值
pathRewrite: {'^/api2': ''}
}
}
}
}
- 组件代码不变,然后继续访问
解决方式3:如果是springboot项目的话,只需要在对应的controller层加上@CrossOrigin注解
Ajax库-vue-resource
- vue 插件库, vue1.x 使用广泛,官方已不维护。交给别的团队维护了,因此不推荐使用该方式。
- 安装vue-resource:
npm i vue-resource
- 引用:
//引入插件 import vueResource from 'vue-resource'
//使用插件,这样vm和vc身上都会有$http Vue.use(vueResource)
- 具体使用方式和axios区别就是把axios.get改成this.$http.get,其他都一样
slot 插槽
作用:
- 让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件
理解:
- 父组件向子组件传递带数据的标签,当一个组件有不确定的结构时, 就需要使用slot 技术
- 注意:插槽内容是在父组件中编译后, 再传递给子组件的
分类:
- 默认插槽
- 具名插槽
- 作用域插槽
默认插槽
-
插槽中的元素是在父组件完成解析之后塞到子组件的,所以样式写在父组件或子组件都行,如果写在父组件会把样式带好传过去,如果写在子组件样式也能控制
-
父组件:
<Category> <html结构>xxxx</html结构> </Category>
-
子组件:
<template> <div> <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) --> <slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> </div> </template>
代码示例
父组件
<template>
<div id="app">
<!-- <Category title="阵营分类" :list="aroundList"></Category>
<Category title="角色分类" :list="roleList"></Category>
<Category title="位置分类" :list="addressList"></Category> -->
<!-- 默认插槽 -->
<div id="category1">
<Category title="阵营分类">
<ul>
<li v-for="(aStr,index) in aroundList" :key="index">{{aStr}}</li>
</ul>
<img src="./assets/1.webp" alt="卡莎"/>
</Category>
<Category title="角色分类" :list="roleList">
<ul>
<li v-for="(rStr,index) in roleList" :key="index">{{rStr}}</li>
</ul>
<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
</Category>
<Category title="位置分类" :list="addressList">
</Category>
</div>
<hr/>
</div>
</template>
<script>
import Category from './components/Category.vue'
export default {
name: 'app',
components: {
Category
},
data(){
return{
aroundList:['德玛西亚','艾欧尼亚','影流','恕瑞玛','均衡教派'],
roleList:['战士','法师','坦克','射手','刺客'],
addressList:['上单','打野','中单','ADC','辅助']
}
}
}
</script>
<style>
#category1,#category2,#category3,.baidu {
display: flex;
justify-content: space-around;
}
img,video{
width: 100%;
}
</style>
子组件
<template>
<div id="category">
<h3>{{title}}</h3>
<!-- 定义一个插槽,父组件使用<Category><标签></标签></Category>时,
会将<标签></标签>传到这里 -->
<slot>默认显示一些值,若没有传递具体结果过来,则显示这些内容</slot>
<!-- <ul>
<li v-for="(item,index) in list" :key="index">
{{item}}
</li>
</ul> -->
</div>
</template>
<script>
export default{
// eslint-disable-next-line vue/multi-word-component-names
name:'Category',
props:['title'],
data(){
return{
}
}
}
</script>
<style scoped>
#category{
background-color: orange;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: skyblue;
}
</style>
具名插槽
-
vue2.6新提出了一个 slot="center"写法 ,且新写法: v-slot:footer ,但只能在 template 用
-
父组件:
<Category> <template slot="center"><div>html结构1</div></template> <template v-slot:footer><div>html结构2</div></template> </Category>
-
子组件:
<template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>
代码示例
父组件
<template>
<div id="app">
<!-- <Category title="阵营分类" :list="aroundList"></Category>
<Category title="角色分类" :list="roleList"></Category>
<Category title="位置分类" :list="addressList"></Category> -->
<div id="category2">
<Category2 title="阵营分类">
<ul slot="liValue">
<li v-for="(aStr2,index2) in aroundList" :key="index2">{{aStr2}}</li>
</ul>
<img slot="staticFile" src="./assets/1.webp" alt="卡莎"/>
</Category2>
<Category2 title="角色分类" :list="roleList">
<video slot="liValue" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
<!-- <template slot="staticFile"> -->
<template v-slot:staticFile>
<div class="baidu">
<a slot="staticFile" href="www.baidu.com">百度一下</a>
<a slot="staticFile" href="www.baidu.com">百度两下</a>
</div>
<h4>百度三下</h4>
</template>
</Category2>
<Category2 title="位置分类" :list="addressList">
</Category2>
</div>
<hr/>
</div>
</template>
<script>
import Category2 from './components/Category2.vue'
export default {
name: 'app',
components: {
Category2
},
data(){
return{
aroundList:['德玛西亚','艾欧尼亚','影流','恕瑞玛','均衡教派'],
roleList:['战士','法师','坦克','射手','刺客'],
addressList:['上单','打野','中单','ADC','辅助']
}
}
}
</script>
<style>
#category1,#category2,#category3,.baidu {
display: flex;
justify-content: space-around;
}
img,video{
width: 100%;
}
</style>
子组件
<template>
<div id="category">
<h3>{{title}}</h3>
<!-- 定义一个插槽,父组件使用<Category><标签></标签></Category>时,
会将<标签></标签>传到这里 -->
<slot name="liValue">liValue:默认显示一些值,若没有传递具体结果过来,则显示这些内容</slot>
<slot name="staticFile">staticFile:默认显示一些值,若没有传递具体结果过来,则显示这些内容</slot>
</div>
</template>
<script>
export default{
// eslint-disable-next-line vue/multi-word-component-names
name:'Category2',
props:['title'],
data(){
return{
}
}
}
</script>
<style scoped>
#category{
background-color: orange;
width: 200px;
height: 320px;
}
h3{
text-align: center;
background-color: skyblue;
}
</style>
作用域插槽
-
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定
-
games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定
-
父组件:
<Category> <template scope="list"> <div>{{list.xx}}</div> </template> </Category>
-
子组件:
<template> <div> <!-- 定义插槽 --> <slot :xx="xxxx" :yy="yyyy" zz="zzzz">插槽默认内容...</slot> </div> </template>
代码示例
父组件
<template>
<div id="app">
<!-- <Category title="阵营分类" :list="aroundList"></Category>
<Category title="角色分类" :list="roleList"></Category>
<Category title="位置分类" :list="addressList"></Category> -->
<div id="category3">
<Category3 title="阵营分类">
<template scope="list">
<ul>
<li v-for="(aStr3,index3) in list.aroundList3" :key="index3">{{aStr3}}</li>
</ul>
<img src="./assets/1.webp" alt="卡莎"/>
</template>
</Category3>
<Category3 title="角色分类">
<template scope="list">
<ul>
<li v-for="(rStr3,index3) in list.roleList3" :key="index3">{{rStr3}}</li>
</ul>
<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
</template>
</Category3>
<Category3 title="位置分类">
</Category3>
<Category3 title="百度一下">
<template scope="list">
<h4>{{list.baidu}}</h4>
</template>
</Category3>
</div>
</div>
</template>
<script>
import Category3 from './components/Category3.vue'
export default {
name: 'app',
components: {
Category3
},
data(){
return{
aroundList:['德玛西亚','艾欧尼亚','影流','恕瑞玛','均衡教派'],
roleList:['战士','法师','坦克','射手','刺客'],
addressList:['上单','打野','中单','ADC','辅助']
}
}
}
</script>
<style>
#category1,#category2,#category3,.baidu {
display: flex;
justify-content: space-around;
}
img,video{
width: 100%;
}
</style>
子组件
<template>
<div id="category">
<h3>{{title}}</h3>
<!-- 定义一个插槽,父组件使用<Category><标签></标签></Category>时,
会将<标签></标签>传到这里 -->
<slot
:aroundList3="aroundList"
:roleList3="roleList"
:addressList3="addressList"
baidu="百度一下"
>
默认显示一些值,若没有传递具体结果过来,则显示这些内容
</slot>
</div>
</template>
<script>
export default{
name:'Category',
props:['title'],
data(){
return{
aroundList:['德玛西亚','艾欧尼亚','影流','恕瑞玛','均衡教派'],
roleList:['战士','法师','坦克','射手','刺客'],
addressList:['上单','打野','中单','ADC','辅助']
}
}
}
</script>
<style scoped>
#category{
background-color: orange;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: skyblue;
}
</style>
vuex
概念:
- 专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
- Github 地址: https://github.com/vuejs/vuex
什么时候使用 Vuex:
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
Vuex原理图
actions、mutations、state都是由store管理的
使用Vuex
- 安装:
npm i vuex
- 引入:在src下创建store目录,在该目录下创建index.js,然后加入
Vue.use(Vuex)
,在main.js中添加import store from './store'
- 弄出来store
- 让所有vc都能看到store
基本使用
- 初始化数据、配置actions、mutations、state
- actions中的方法命名规范:方法名小写驼峰(context,value),第一个参数context上下文,可以拿到commit、state等,第二个是传过来的值
- mutations中的方法命名规范:方法名大写(state,value)
- 组件中读取vuex中的数据:$store.state.xx
- 组件中修改vuex中的数据:$store.dispatch(‘action中的方法名’,数据)或 $store.commit(‘mutations中的方法名’,数据)
代码示例
src/store/index.js
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
/* jia(context,value){
console.log('actions中的jia被调用了')
context.commit('JIA',value)
},
jian(context,value){
console.log('actions中的jian被调用了')
context.commit('JIAN',value)
}, */
jiaOdd(context,value){
console.log('actions中的jiaOdd被调用了')
if(context.state.sum % 2){
context.commit('JIA',value)
}
},
jiaWait(context,value){
console.log('actions中的jiaWait被调用了')
setTimeout(()=>{
context.commit('JIA',value)
},500)
}
}
//准备mutations——用于操作数据(state)
const mutations = {
JIA(state,value){
console.log('mutations中的JIA被调用了')
state.sum += value
},
JIAN(state,value){
console.log('mutations中的JIAN被调用了')
state.sum -= value
}
}
//准备state——用于存储数据
const state = {
sum:0 //当前的和
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
子组件
<template>
<div>
<h1>当前求和为:{{$store.state.sum}}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data() {
return {
n:1, //用户选择的数字
}
},
methods: {
/* increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
}, */
/* incrementOdd(){
this.$store.dispatch('jiaOdd',this.n)
},
incrementWait(){
this.$store.dispatch('jiaWait',this.n)
}, */
},
mounted() {
console.log('Count',this)
},
}
</script>
<style lang="css">
button{
margin-left: 5px;
}
</style>
main.js:引入store
//引入store
import store from './store'
父组件
<template>
<div id="app">
<Count></Count>
<!-- <button @click="demo">点击</button>
<h1>{{count}}</h1> -->
</div>
</template>
<script>
import Count from './components/Count.vue'
export default {
name: 'app',
components: {
Count
},
data() {
return{
count:0
}
},
methods:{
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
- 备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit