一、脚手架配置代理
1.回顾常用的ajax发送方式:
(1)xhr
比较麻烦,不常用
(2)jQuery
核心是封装dom操作,所以也不常用
(3)axios
优势:体积小、是promise风格的、支持请求拦截器和响应拦截器
(4)fetch
2.3都是封装xhr的,fetch跟xhr平级,直接在window身上就能找到,而且也是promise风格的,但是不兼容,ie肯定不能用;它会把你返回的数据包两层,所以不如axios常用。
2.引出问题
点击按钮获取学生信息,app.vue:
import axios from 'axios'
import { response } from 'express'
export default {
name:'App',
methods:{
getStudent(){
axios.get('http://localhost:5000/students'),then(
response=>{
console.log('请求成功了',response.data)
//response是一个响应对象。data里面的东西才是response想给你的
},
error=>{
console.log('请求失败了',error.message)
//maeeage失败的原因
}
)
}
}
}
点击按钮之后页面报错,出现、、、cors、、、Access-Control-Allow-Oringin说明跨域了,协议、域名、端口号出现不一样的,我们所在的端口号是8080,向端口号5000的要数据,5000给8080了,然后8080发现跨域了就没有给你数据,解决跨域的问题:
1.cors(写服务器的人在服务器加几个响应头)
5000返回的时候还携带几个特殊的响应头,8000看见就给你了
2.jsonp(借助script 的src属性)
src属性在引入外部资源的时候不受同源限制,但是得前端后端一起配合,而且它只能解决get请求的问题,开发不常用但是面试经常问,很巧妙的用法
3.配置一个代理服务器
代理服务器是一个中间人,但是它所处的位置跟我们一样(8080),粉色那个跟我们肯定是同域的,那粉色跟蓝色呢?他俩都是服务器,服务器和服务器之间传输局不用ajax,用的就是http传就完事了。那粉色的8080服务器得怎么开啊?1.nginx,学习成本大偏后端 2.vue-cli,借助vue脚手架。
然后我们就来配置一下代理服务器
(1)方式一:
在vue.config.js:
它的8080不用你管,你只需要告诉这个代理服务器一会要把请求转发给谁就ok,后面具体路径不用写,写到端口号就行
//开启服务代理
devServer:{
proxy:'htp://localhost:5000'
}
app.vue
methods:{
getStudent(){
axios.get('http://localhost:8080/students').then(
response=>{
console.log('请求成功了',response.data)
//response是一个响应对象。data里面的东西才是response想给你的
},
error=>{
console.log('请求失败了',error.message)
//maeeage失败的原因
}
)
}
}
而且这个中间代理也不是什么时候都会转发请求的,如果粉色的自己本身就有就不会往5000找了,public里面文件都算是8080有的。
1、优点:配置简单,请求资源时直接发给前端(8080)即可。
2、缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
3、工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)。
(2)方式二
vue.config.js:
devServer:{
proxy:{
'/ttt':{ //请求前缀,想走代理就在请求的前面加/???,就把东西转发给target
target:'http://localhost:5000',
pathRewrite:{'^/ttt':''},
//不加这个配置粉色找蓝色的时候默认找的/ttt/server1
ws:true ,//用于支持websocket
changeOrigin:true//用于控制请求头的host值
//这个是告诉5000我也来自5000(是true就撒谎来自5000,false就是来自8080),防止5000用不了设置true比较好
},
'/hhh':{
target:'http://localhost:5001',
pathRewrite:{'^/hhh':''},
ws:true ,
changeOrigin:true
},
}
}
app:
getStudent(){
axios.get('http://localhost:8080/ttt/students').then(
//前缀就加在端口号后面,后面正常写
response=>{
console.log('请求成功了',response.data)
//response是一个响应对象。data里面的东西才是response想给你的
},
error=>{
console.log('请求失败了',error.message)
//maeeage失败的原因
}
)
},
getCar(){
axios.get('http://localhost:8080/hhh/cars').then(
//前缀就加在端口号后面,后面正常写
response=>{
console.log('请求成功了',response.data)
//response是一个响应对象。data里面的东西才是response想给你的
},
error=>{
console.log('请求失败了',error.message)
//maeeage失败的原因
}
)
}
如果我自己也有个students它也不会来拿我这个信息,因为加了/ttt就强制去5000那里拿数据了,所以这种就更灵活。
1、优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
2、缺点:配置略微繁琐,请求资源时必须加前缀。
二、github案例
如果第三方库你写在assets里面了就得用import 引用,用import引用会很严重的检查,有某些字体你没有但是你引用了那就显示不出来,但是link方法没事,你没有但是引用了就不显示呗
所以像这种引入了外部资源的就不适合用assets/css/里面,那就放在public/css,然后在index.html中link引用一下,他里面引用了app也能用
接口https虽然案例来说跨域了,但是人家的工程师用cors已经解决了不用我们担心
list首先展示欢迎,用户搜索之后显示 正在加载中 ,加载完毕显示users,加载失败显示error
那怎么判断该显示啥呢?数据驱动页面展示
1.app.vue
<template>
<div class="container">
<mySearch />
<myList />
</div>
</template>
<script>
import mySearch from "./components/mySearch.vue";
import myList from "./components/myList.vue";
export default {
name: "App",
components: { mySearch, myList },
};
</script>
<style>
</style>
2.myList.vue
<template>
<div class="row">
<div
v-show="info.users.length"
class="card"
v-for="user in info.users"
:key="user.login"
>
<a :href="user.html_url" target="_blank">
<img :src="user.avatar_url" style="width: 100px" />
<!-- 头像地址 -->
</a>
<p class="card-text">{{ user.login }}</p>
<!-- 用户名 -->
</div>
<!-- 欢迎词 -->
<h1 v-show="info.isFirst">欢迎!</h1>
<!-- 加载中 -->
<h1 v-show="info.isLoading">加载中······</h1>
<!-- 错误信息 -->
<h1 v-show="info.errMsg">{{ info.errMsg }}</h1>
<!-- 都一样就不一个一个写了,但是这次也不用item,直接v-for -->
</div>
</template>
<script>
export default {
name: "myList",
data() {
return {
info: {
isFirst: true, //是不是初次展示
isLoading: false, //点击按钮之后才加载
errMsg: "", //不能用布尔值了,得看看是网差还是别的原因呢导致的
users: [],
//这些东西都得听search的,情况不同他们几个值也变
},
};
},
mounted() {
this.$bus.$on('updateListData', (dataObj) => {
this.info={...this.dataObj,...dataObj}//es6规则,俩人都有的按后边来,前面没有的要后面的
//这里不要this.data=dataObj,更不能this._data,赋值过去动了原本配置的getter、setter
});
},
};
</script>
<style scoped>
.album {
min-height: 50rem; /* Can be removed; just added for demo purposes */
padding-top: 3rem;
padding-bottom: 3rem;
background-color: #f7f7f7;
}
.card {
float: left;
width: 33.333%;
padding: 0.75rem;
margin-bottom: 2rem;
border: 1px solid #efefef;
text-align: center;
}
.card > img {
margin-bottom: 0.75rem;
border-radius: 100px;
}
.card-text {
font-size: 85%;
}
</style>
3.mySearch.vue
<template>
<section class="jumbotron">
<h3 class="jumbotron-heading">Search Github Users</h3>
<div>
<input
type="text"
placeholder="enter the name you search"
v-model="keyword"/>
<button @click="searchUsers">Search</button>
</div>
</section>
</template>
<script>
import axios from 'axios'
//import { response } from 'express';
export default {
name:'mySearch',
data(){
return {
keyword:''
}
},
methods:{
searchUsers(){
//请求前更新list的数据
this.$bus.$emit('updateListData',{isFirst:false,isLoading:true,errMsg:'',users:[]})
axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
response=>
{
this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
// 就最开始欢迎一下,之后就不用了,但是直接不写之后就少一个属性,用es6语法解决
console.log('请求成功',response.data.items)
this.$bus.$emit('getUsers',response.data.items)
},
error=>{
this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
console.log('请求失败',error.message)
}
)
// 直接等于this.??他肯定不按js给你解析,模版字符串然后$
}
}
};
</script>
<style>
</style>
4.vue-resource
也是对xhr的封装,安装插件 :npm i vue-resource
就是把axios替换成了this.$http,其他的都一样
main.js引入插件:import vueResource from 'vue-resource'
使用插件:Vue.use(vueResource)
维护的不频繁用的不多
三、插槽
1.默认插槽
如果我想在最小的组件(重复的)的其中一个里面添加图片,和其他组件都不一样的话,我直接在<category> <img、、、></category>这样写出不来图片,因为人家解析到img之后不知道来到category.vue里人家就不知道把img给你放哪儿了。
用一个特殊的标签slot,告诉人家识别完不知道放哪儿的标签放在哪个位置
(1)app.vue
<template>
<div class="container">
<myCategory title="美食">
<img src="http://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="" />
</myCategory>
<myCategory title="游戏">
<ul>
<li v-for="(g, index) in games" :key="index">{{ g }}</li>
</ul>
</myCategory>
<!-- 这三个的样式都是解析完之后才塞到myCategory里面去的,所以script可以直接写在app里 -->
<myCategory title="电影">
<video
controls
src="http://clips.vorwaerts-gmbh.de/big_buck.bunny.mp4"
></video>
</myCategory>
<!-- :foods=foods那得传太多了,很麻烦 -->
</div>
</template>
<script>
import myCategory from "./components/myCategory.vue";
export default {
name: "App",
components: { myCategory },
data() {
return {
foods: ["火锅", "烧烤", "小龙虾", "牛排"],
games: ["战神4", "极品飞车", "鬼泣", "超级玛丽"],
films: ["《教父》", "《复仇者联盟》", "《绿皮书》", "《阿甘》"],
};
},
};
</script>
<style>
.container {
display: flex;
justify-content: space-around;
}
img {
width: 100%;
}
video {
width: 100%;
}
</style>
(2)myCategory.vue
<template>
<div class="category">
<h3>{{ title }}</h3>
<slot>图片加载不出来会看见这些文字</slot>
<!-- 挖坑等组件的使用者进行填充 -->
</div>
</template>
<script>
export default {
name: "myCategory",
props: ["listData", "title"],
};
</script>
<style>
.category {
background-color: aqua;
width: 200px;
height: 300px;
}
h3 {
text-align: center;
background-color: orange;
}
</style>
2.具名插槽
刚才那个只有一个,直接用的slot,具名插槽就是具有名字的插槽
app:
<template>
<div class="container">
<myCategory title="美食">
<img
slot="center"
src="http://s3.ax1x.com/2021/01/16/srJlq0.jpg"
alt=""
/>
<a slot="footer" href="">更多美食</a>
</myCategory>
<myCategory title="游戏">
<ul slot="center">
<li v-for="(g, index) in games" :key="index">{{ g }}</li>
</ul>
<div class="foot" slot="footer">
<a href="">单机游戏</a>
<a href="">更多美食</a>
</div>
<!-- 这个可以追加 -->
</myCategory>
<!-- 这三个的样式都是解析完之后才塞到myCategory里面去的,所以script可以直接写在app里 -->
<myCategory title="电影">
<video
slot="center"
controls
src="http://clips.vorwaerts-gmbh.de/big_buck.bunny.mp4"
></video>
<template v-slot:footer>
<!-- 这样slot写一次就可以了 因为template slot就可以这样写了,只有它行-->
<div class="foot">
<a href="">单机游戏</a>
<a href="">更多美食</a>
<a href="">更多美食</a>
</div>
<h4>欢迎前来观影</h4>
</template>
</myCategory>
<!-- :foods=foods那得传太多了,很麻烦 -->
</div>
</template>
mycategory:
<template>
<div class="category">
<h3>{{ title }}</h3>
<slot name="center">图片加载不出来会看见这些文字</slot>
<slot name="footer">图片加载不出来会看见这些文字</slot>
<!-- 挖坑等组件的使用者进行填充 -->
</div>
</template>
3.作用域插槽
现在我们只留下游戏重复三个,然后设计第一个是无序列表,第二个有序,第三个每一个游戏都是h4标题
我把数据交给了插槽的使用者,根据数据所生成的结构由使用者来定
app:
<template>
<div class="container">
<myCategory title="游戏">
<template scope="atguigu">
<!-- atguigu收过来的是一个对象 -->
<ul>
<li v-for="(g, index) in atguigu.games" :key="index">{{ g }}</li>
</ul>
</template>
</myCategory>
<myCategory title="游戏">
<template scope="{games}">
<!-- 结构赋值 -->
<!-- atguigu收过来的是一个对象 -->
<ol>
<li v-for="(g, index) in games" :key="index">{{ g }}</li>
</ol>
</template>
</myCategory>
<myCategory title="游戏">
<template slot-scope="{games}">
<h4 v-for="(g, index) in games" :key="index">{{ g }}</h4>
</template>
</myCategory>
</div>
</template>
<script>
import myCategory from "./components/myCategory.vue";
export default {
name: "App",
components: { myCategory },
};
</script>
<style>
.container,
.foot {
display: flex;
justify-content: space-around;
}
img {
width: 100%;
}
video {
width: 100%;
}
h4 {
text-align: center;
}
</style>
category:
<template>
<div class="category">
<h3>{{ title }}</h3>
<slot :games="games">我是默认内容</slot>
<!-- 我在这里写了一个games,那么它就把games传给了插槽的使用者app里 -->
</div>
</template>
<script>
export default {
name: "myCategory",
props: ["listData", "title"],
data() {
return {
games: ["战神4", "极品飞车", "鬼泣", "超级玛丽"],
};
},
};
</script>
<style>
.category {
background-color: aqua;
width: 200px;
height: 300px;
}
h3 {
text-align: center;
background-color: orange;
}
</style>