不管何时何地,永远保持热爱,永远积极向上!!!
【19.尚硅谷GitHub案例】
 
1.静态GitHub搜索案例的静态文件:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <!-- 引入第三方样式库bootstrap.css -->
  <link rel="stylesheet" href="./bootstrap.css">
  <link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="app">
  <div class="container">
    <section class="jumbotron">
      <h3 class="jumbotron-heading">Search Github Users</h3>
      <div>
        <input type="text" placeholder="enter the name you search"/> <button>Search</button>
      </div>
    </section>
    <div class="row">
      <div class="card">
        <a href="https://github.com/xxxxxx" target="_blank">
          <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
        </a>
        <p class="card-text">xxxxxx</p>
      </div>
      <div class="card">
        <a href="https://github.com/xxxxxx" target="_blank">
          <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
        </a>
        <p class="card-text">xxxxxx</p>
      </div>
      <div class="card">
        <a href="https://github.com/xxxxxx" target="_blank">
          <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
        </a>
        <p class="card-text">xxxxxx</p>
      </div>
      <div class="card">
        <a href="https://github.com/xxxxxx" target="_blank">
          <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
        </a>
        <p class="card-text">xxxxxx</p>
      </div>
      <div class="card">
        <a href="https://github.com/xxxxxx" target="_blank">
          <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
        </a>
        <p class="card-text">xxxxxx</p>
      </div>
    </div>
  </div>
</div>
</body>
</html>
index.css
.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: .75rem;
  margin-bottom: 2rem;
  border: 1px solid #efefef;
  text-align: center;
}
.card > img {
  margin-bottom: .75rem;
  border-radius: 100px;
}
.card-text {
  font-size: 85%;
}
bootstrap.css: 引入第三方样式库bootstrap.css。 
- 静态页面展示:并拆分为两个组件【上方:Search.vue组件 + 下方:List.vue组件 】

2.基于代理服务器的GitHub搜索案例
- 第三方样式库放置的位置如下:

-  并在 index.html文件中引入:<!-- 引入第三方样式库 --> <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">
-  拆分改写完后,展示: 

-  github接口地址:【 https://api.github.com/search/users?q=xxx】这是github维护的一个简单测试接口,其中xxx为:输入的内容,github接口就会返回xxx相关的数据。
-  axios的get请求url拼接参数有2种方式: -  方式1:字符串+拼接 axios.get('https://api.github.com/search/users?q='+this.keyWord).then()
-  方式2:采用ES6语法,地址字符串采用反单引号【``】,同时使用**【${}】**【不是单引号,不是单引号!!!】 axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then()
 
-  
目前效果的展示以及动图中两个错误的解决办法如下:
- 错误1:DevTools failed to load source map: Could not load content for http://localhost:8080/css/bootstrap.css.map: HTTP 错误:状态代码 404,net::ERR_HTTP_RESPONSE_CODE_FAILURE【点击此处】删掉bootstrap.css文件中的最后一行代码:【/*# sourceMappingURL=bootstrap.css.map */】
- 错误2:【图片加载报错的点击此处】

请求数据解释:
- total_counter:总的数据量
- incomplete_results: false【不会把所有的数据给你】
- items:实际搜索到的数据量

目前代码为:
App.vue
<template>
	<div class="container">
		<Search/>
		<List/>
	</div>
</template>
<script>
import List from './components/List';
import Search from './components/Search';
export default {
	components: { List, Search},
	name: 'App',
};
</script>
Search.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';
export default {
	name: 'Search',
  data() {
    return {
      keyWord:'',
    }
  },
	methods: {
		searchUsers() {
      // 获取该url:github搜索的数据
      axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
        //请求成功后
        (response)=>{
          console.log(response.data);
        },
        //请求失败后
        (error)=>{
          console.log('我请求数据失败了');
        },
      );
		},
	},
};
</script>
<style></style>
List.vue
<template>
	<div class="row">
		<div class="card">
			<a href="https://github.com/xxxxxx" target="_blank">
				<img
					src="https://v2.cn.vuejs.org/images/logo.svg "
					style="width: 100px"
				/>
			</a>
			<p class="card-text">xxxxxx</p>
		</div>
		<div class="card">
			<a href="https://github.com/xxxxxx" target="_blank">
				<img
					src="https://v2.cn.vuejs.org/images/logo.svg "
					style="width: 100px"
				/>
			</a>
			<p class="card-text">xxxxxx</p>
		</div>
		<div class="card">
			<a href="https://github.com/xxxxxx" target="_blank">
				<img
					src="https://v2.cn.vuejs.org/images/logo.svg "
					style="width: 100px"
				/>
			</a>
			<p class="card-text">xxxxxx</p>
		</div>
		<div class="card">
			<a href="https://github.com/xxxxxx" target="_blank">
				<img
					src="https://v2.cn.vuejs.org/images/logo.svg "
					style="width: 100px"
				/>
			</a>
			<p class="card-text">xxxxxx</p>
		</div>
		<div class="card">
			<a href="https://github.com/xxxxxx" target="_blank">
				<img
					src="https://v2.cn.vuejs.org/images/logo.svg "
					style="width: 100px"
				/>
			</a>
			<p class="card-text">xxxxxx</p>
		</div>
	</div>
</template>
<script>
export default {};
</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: .75rem;
		margin-bottom: 2rem;
		border: 1px solid #efefef;
		text-align: center;
	}
	.card > img {
		margin-bottom: .75rem;
		border-radius: 100px;
	}
	.card-text {
		font-size: 85%;
	}
</style>
- 然后,把Search组件拿到的数据怎么在页面展示出来:涉及Search组件【给数据】与List组件【接收数据】之间的通信【兄弟组件之间通信:1.全局数据总线 或 2.消息的订阅与发布】
- 拿到items这个大数据,里面有30条小数据,每一条数据包含的属性如下:

- 利用全局事件总线实现组件之间的通信,并且将收到数据在页面展示出来,初步效果如下:
- 【注意】绑定数据时,一定要动态绑定,一定要加冒号,比如下面代码中的【 :src=“user.avatar_url”】

此时代码为:
main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
  // 生命周期钩子beforeCreate中模板未解析,且this是vm
  beforeCreate() {
    // this:指的是vm
		Vue.prototype.$bus = this  //安装全局事件总线$bus
	}
})
App.vue组件不变
Search.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';
export default {
	name: 'Search',
  data() {
    return {
      keyWord:'',
    }
  },
	methods: {
		searchUsers() {
      // 获取该url:github搜索的数据
			axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
        //请求成功后触发自定义事件,并传递数据
        (response)=>{
          console.log(this);// this指vc
          console.log(response.data);
          this.$bus.$emit('updateListData',response.data.items)
        },
        //请求失败后
        (error)=>{
          console.log('我请求数据失败了');
          this.$bus.$emit('updateListData',response.data.items)
        },
      );
		},
	},
};
</script>
List.vue
<template>
	<div class="row">
    <!-- 展示用户列表 -->
		<div class="card"
    v-show="users.length"
    v-for="user in 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>
	</div>
</template>
<script>
export default {
	name: 'List',
	data() {
		return {
      users:[],
    };
	},
  // 全局数据总线:
  // 接收数据的一方:在mounted钩子中定义自定义事件
  mounted() {
    // 绑定事件updateListData,并在回调函数中接收来自Search组件的数据【对象的形式:dataObj】
    this.$bus.$on('updateListData',(dataObj) => {
      this.users=dataObj
    })
  },
};
</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>
-  继续完善页面: -  1、数据加载之前,页面展示:欢迎词!! <!-- 展示欢迎词 --> <h2 v-show="info.isFirst">欢迎使用免费的GitHub接口!</h2>
-  2、数据加载中,页面展示:加载中!! <!-- 展示加载中 --> <h2 v-show="info.isLoading">页面加载中....</h2>
-  3、数据加载错误,页面展示:错误信息!! <!-- 展示错误信息 --> <h2 v-show="info.errorMsg">{{ info.errorMsg }}</h2>
 
-  
-  全局事件总线传多个参数方式有以下几种: this.$bus.$emit('自定义事件',传递的参数)-  方式1:直接传多个参数: this.$bus.$emit('updateListData', true, false, '', [])- 缺点1:不优雅不直观,不写注释压根不知道传过去的true、false、’’、[]啥意思;
- 缺点2:接收方必须按照索引顺序才能正确获取参数。
 
-  方式2:传过去的参数封装成json对象方式: this.$bus.$emit('updateListData',{isLoading:true,errorMsg:'',users:[]})
-  接收方:接收方式2传过来的数据,然后通过整个对象赋值。 - 缺点:会丢失属性值,data函数有4个属性,而传递过来的dataObj对象只有3个属性,那么通过整个对象赋值后,最后控制台会整个替换从而丢失一个isFirst属性。
- 为什么传递过来的dataObj对象只有3个属性:因为isFirst属性在最初页面展示完欢迎词后,就变为false了,后续都不会再变化了,所以,不用再传isFirst属性了。
 
 data() { return { info:{ isFirst:true, isLoading:false, errMsg:'', users:[] } } }, mounted() { this.$bus.$on('updateListData',(dataObj)=>{ this.info= dataObj; }) },
-  
-  通过ES6语法实现局部更新,语法:{…原数据,…接收数据}:dataObj没有的属性用data() 原有的,dataObj包含的属性采用dataObj传递过来的值,另一个好处传递方不按属性顺序传值也能接收。传递方,比如data()中isFirst为第一个属性,而我传递时放在了{}的最后也有效。 // 对象合并:相同的属性以后面的对象为主 this.info = {...this.info,...dataObj}
-  问题:如下面代码一样,可以把dataObj直接复制给this._data中吗? data() { return { isFirst:true, isLoading:false, errMsg:'', users:[] } }, mounted() { this.$bus.$on('updateListData',(dataObj)=>{ this._data= dataObj; }) },- 不能,如果赋值给this._data就破坏数据结构了,因为直接赋值方式不会让vue动态代理给_data中配置get和set方法,没有响应了。
 
- 不能,如果赋值给
-  最终完善后的效果如下: 

完整代码:
- index.html
<!DOCTYPE html>
<html lang="zh-en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- 引入第三方样式库 -->
    <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
-  main.js文件//引入Vue import Vue from 'vue' //引入App import App from './App.vue' //关闭Vue的生产提示 Vue.config.productionTip = false //创建vm new Vue({ el:'#app', render: h => h(App), // 生命周期钩子beforeCreate中模板未解析,且this是vm beforeCreate() { // this:指的是vm Vue.prototype.$bus = this //安装全局事件总线$bus } })
-  App.vue文件<template> <div class="container"> <Search/> <List/> </div> </template> <script> import List from './components/List'; import Search from './components/Search'; export default { components: { List, Search}, name: 'App', }; </script>
-  Search.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'; export default { name: 'Search', data() { return { keyWord:'', } }, methods: { searchUsers() { //请求前更新List的数据 this.$bus.$emit('updateListData',{isLoading:true,errorMsg:'',users:[],isFirst:false}) // 获取该url:github搜索的数据 axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then( //请求成功后触发自定义事件,并传递数据 (response)=>{ console.log(this);// this指vc console.log(response.data); this.$bus.$emit('updateListData',{isLoading:false,errorMsg:'',users:response.data.items}) }, //请求失败后 (error)=>{ console.log('我请求数据失败后,传递失败的信息,并将users数据初始化'); // 请求失败后 users必须制空,不然页面还是会显示上次成功请求的数据 this.$bus.$emit('updateListData',{isLoading:false,errorMsg:error.message,users:[]}) }, ); }, }, }; </script>
-  List.vue文件<template> <div class="row"> <!-- 展示用户列表 --> <div class="card" v-show="info.users.length" 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> <!-- 展示欢迎词 --> <h2 v-show="info.isFirst">欢迎使用免费的GitHub接口!</h2> <!-- 展示加载中 --> <h2 v-show="info.isLoading">页面加载中....</h2> <!-- 展示错误信息 --> <h2 v-show="info.errorMsg">{{ info.errorMsg }}</h2> </div> </template> <script> export default { name: 'List', data() { return { info: { isFirst: true, isLoading: false, errorMsg: '', users: [], }, }; }, // 全局数据总线: // 接收数据的一方:在mounted钩子中定义自定义事件 mounted() { // 绑定事件updateListData,并在回调函数中接收来自Search组件的数据【对象的形式:dataObj】 this.$bus.$on('updateListData', (dataObj) => { // 对象合并:相同的属性以后面的对象为主 this.info = {...this.info,...dataObj} }); }, }; </script> <style scoped> h2 { margin-left: 50px; } .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>



















