不管何时何地,永远保持热爱,永远积极向上!!!
【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>