一、脚手架配置代理

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"/>&nbsp;
      <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>
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐