• Vue项目实战——实现GitHub搜索案例(学以致用,两小时带你巩固和强化Vue知识点)


    Vue2.x 项目实战(二)

    内容参考链接
    Vue2.x全家桶Vue2.x 全家桶参考链接
    Vue2.x项目(一)Vue2.x 实现一个任务清单
    Vue2.x项目(二)Vue2.x 实现GitHub搜索案例
    Vue3.x项目(三)Vue3.x 实现一个任务清单


    Vue2.x 实现 github 搜索案例

    1、前言

    如果你对 vue 的基础知识还很陌生,推荐先去学习一下 vue 基础

    本篇文章依旧是使用的 Vue 基础知识,同时新增了 axios 请求数据 的需求,及 兄弟组件间 如何 使用自定义事件 实现组件间通信

    • 如果你 刚学完 vue 基础知识,想检查一下自己的学习成果
    • 如果你 已学完 vue 基础知识,想快速回顾复习
    • 如果你 已精通 vue 基础知识,想做个小案例
    • 那不妨 再看完这篇文章我保证你一定会更有收获的!

    2、项目演示(一睹为快)

    github 搜索案例

    在这里插入图片描述

    3、涉及知识点

    • Vue基础:插值语法,常用指令,列表渲染,生命周期
    • Vue进阶:自定义事件(兄弟组件间通信),自定义事件的解绑
    • 第三方库:axios(发送 axios 请求,请求数据),vue-lazyload 插件,实现 图片懒加载

    备注:

    1. 任意组件间的通信方式有很多种(全局事件总线,消息订阅预发布…),熟练掌握一种即可
    2. 本文是 vue 基础的练习项目,不涉及 vue 周边(Vuex,Vue-router)

    4、项目详情(附源码及解析)

    该项目包含三个 vue 组件

    (1)App.vue 父组件:整合子组件

    (2)Search.vue 子组件:用户查询,发送请求,获取数据

    (3)List.vue 子组件:展示用户图片和信息的列表

    备注:

    1. github 提供的请求 API:https://api.github.com/search/users?q=xxx
    2. 请求的数据(用到的红框起来了)
      在这里插入图片描述

    App.vue 父组件

    <template>
      <div class="container">
        <Search />
        <List />
      </div>
    </template>
    
    <script>
    import Search from "./components/Search.vue";
    import List from "./components/List.vue";
    export default {
      name: "App",
      components: { Search, List },
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Search.vue 子组件

    • 终端键入 npm i axios 安装 axios
    • 给按钮添加点击事件,axios 请求数据并进行页面的渲染更新
    • 兄弟组件间通过自定义事件通信,要引入一个 event.js 文件,暴露一个 vue 实例
    <template>
      <section class="jumbotron">
        <h3 class="jumbotron-heading">Search Github Users</h3>
        <input
          type="text"
          placeholder="enter the name you search"
          v-model="keyWords"
        />&nbsp;
        <button @click="searchUsers">Search</button>
      </section>
    </template>
    
    <script>
    import axios from "axios";
    import event from '../event'
    export default {
      name: "mySearch",
      data() {
        return {
          keyWords: "", // 用户输入的关键字
        };
      },
      methods: {
        // 查询用户
        searchUsers() {
          // 请求前更新 List 的数据
          event.$emit("updateListData", {
            isFirst: false, // 隐藏欢迎词
            isLoading: true, // 展示加载中...
            errMsg: "", // 错误信息为空
            users: [], // 数据置为空
          });
          axios.get(`https://api.github.com/search/users?q=${this.keyWords}`).then(
            // 成功的回调,隐藏欢迎和加载中,展示请求出来的数据
            (reponse) => {
              console.log("请求成功了", reponse.data.items);
              // 请求成功后更新 List 数据
              event.$emit("updateListData", {
                isLoading: false, // 请求成功,隐藏加载中...
                errMsg: "",
                users: reponse.data.items, // users 数组存放请求成功的数据
              });
            },
    		// 失败的回调,提示错误信息
            (error) => {
              //请求失败后更新List数据
              console.log("请求失败了", error.message);
              event.$emit("updateListData", {
                isLoading: false, // 请求成功,隐藏加载中...
                errMsg: error.message, // 请求出错,展示错误信息
                users: [], // users 数组置空
              });
            }
          );
        },
      },
    };
    </script>
    
    <style>
    .jumbotron {
      margin-top: 20px;
    }
    .jumbotron-heading {
      color: skyblue;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    List.vue 子组件

    • 终端键入 npm i vue-lazyload 安装懒加载插件
    • 在 main.js 中导入并使用它,并设置懒加载时的图片
    • 兄弟组件间通过自定义事件通信,要引入一个 event.js 文件,暴露一个 vue 实例
    <template>
      <div class="row">
        <!-- 展示用户列表,没有内容时隐藏它。user.login,是唯一标识 -->
        <div
          v-show="info.users.length"
          class="card"
          v-for="user in info.users"
          :key="user.login"
        >
          <!-- 动态绑定用户的主页地址和图片地址 -->
          <a :href="user.html_url" target="_blank">
          	<!-- v-lazy 实现图片的懒加载 -->
            <img v-lazy="user.avatar_url" style="width: 100px; height: 100px" />
          </a>
          <!-- 呈现用户名 -->
          <p class="card-text">{{ user.login }}</p>
        </div>
        <!-- 初始页面,展示欢迎词 -->
        <h2 class="welcome" v-show="info.isFirst">前端杂货铺,欢迎你的使用!</h2>
        <!-- 点击查询,加载过程中展示加载中 -->
        <h2 class="loading" v-show="info.isLoading">加载中...</h2>
        <!-- 请求出错,展示错误信息 -->
        <h2 class="error" v-show="info.errMsg">{{ info.errMsg }}</h2>
      </div>
    </template>
    
    <script>
    import event from "../event";
    export default {
      name: "myList",
      data() {
        return {
          info: {
            isFirst: true, // 欢迎词
            isLoading: false, // 加载中...
            errMsg: "", // 错误信息
            users: [], // 存放用户的数组
          },
        };
      },
      // 挂载时绑定自定义事件
      mounted() {
        event.$on("updateListData", (dataObj) => {
          // 合并这两个对象,并且同 key 值的后面的会覆盖前面的,这样 isFirst 就不用重复写了
          this.info = { ...this.info, ...dataObj };
        });
      },
      // 销毁前解绑自定义事件
      beforeDestroy() {
        event.$off("updateListData");
      },
    };
    </script>
    
    <style scoped>
    .welcome {
      color: orange;
    }
    .loading {
      color: rgb(0, 162, 255);
    }
    .error {
      color: red;
    }
    .album {
      min-height: 50rem;
      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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    main.js 文件

    import Vue from 'vue'
    import App from './App.vue'
    import VueLazyload from 'vue-lazyload'
    
    // 使用懒加载,并设置加载时的图片
    Vue.use(VueLazyload, {
        loading: require("./assets/loading3.png")
    })
    
    new Vue({
        el:'#app',
        render: h => h(App),
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    event.js 文件

    • 暴露一个 vue 实例,供自定义事件进行兄弟组件间的通信
    import Vue from 'vue'
    
    export default new Vue()
    
    • 1
    • 2
    • 3

    5、写在最后的话

    如果你是 看完全篇 阅读到了这里,我相信你一定是有收获的!

    那么下面不妨打开自己的电脑,启动自己的编译器,来跟着做 / 自己做一遍吧!


    在这里插入图片描述


  • 相关阅读:
    什么是grep命令?
    多线程会遇到的问题与解决方法
    对人脸图像进行性别和年龄的判断
    HDU 2089 不要62(数位DP,DFS写法)
    基于智能远程监考方案,云上组考打造考试新范式
    Android 开发错误集合
    kube-ovn安装与卸载
    游戏设计模式专栏(八):Cocos中最常见的设计模式之一
    【教学类-20-02】20221203《世界杯16强国旗-定量版》(大班)
    Python内置函数/方法详解—元组tuple
  • 原文地址:https://blog.csdn.net/qq_45902692/article/details/126751629