vue 响应式ui_如何在Vue.js中设置响应式UI搜索

vue 响应式ui

Are you thinking of building something awesome with one of the popular modern frameworks out there right now, but don’t know how to get started?

您是否正在考虑使用当前流行的现代框架之一来构建出色的东西,但不知道如何入门?

If yes, then this post will help you get a kick started and build something awesome.

如果是的话,那么这篇文章将帮助您入门并建立一些很棒的东西。

What are we going to build?

我们要建造什么?

We will be building a responsive client side search of the 7 wonders of the world with the following features:

我们将通过以下功能对世界7大奇观进行响应式客户端搜索:

  1. Text Search & Filters based on Ratings and Likes.

    基于评级和喜欢的文本搜索过滤器

  2. 2 items per row for Tablet and Desktop, 1 item per row for Mobile.

    平板电脑台式机每行2项, 移动设备每行1项。

  3. Fetching data asynchronously from external API on client side.

    从客户端的外部API异步获取数据。
  4. Responsive view as shown below:

    响应视图如下图:

Live Demo: https://vue-responsive-search.herokuapp.com

现场演示https : //vue-sensitive-search.herokuapp.com

Source Code: https://github.com/honey93/VueSearchExample

源代码https : //github.com/honey93/VueSearchExample

科技架构 (Tech Architecture)

We will be working with the following technologies:

我们将使用以下技术:

  1. Vue.js: The Progressive JavaScript Framework

    Vue.js 渐进式JavaScript框架

  2. BootstrapVue: It provides one of the most comprehensive implementations of Bootstrap V4 components and grid system available for Vue.js 2.5+, complete with extensive and automated WAI-ARIA accessibility markup.

    BootstrapVue 它提供了适用于Vue.js 2.5+的Bootstrap V4组件和网格系统的最全面的实现之一,并带有大量且自动的WAI-ARIA可访问性标记。

  3. Vue Cli 3: Standard Tooling for Vue.js Development

    Vue Cli 3 用于Vue.js开发的标准工具

项目结构 (Project Structure)

To get started with our Vue project, we need to setup many things like Vue, Bootstrap, Vue Router, Vuex, etc.

要开始我们的Vue项目,我们需要设置许多东西,例如Vue,Bootstrap,Vue Router,Vuex等。

Vue Cli provides us the command to create the project with most of the needed configurations.

Vue Cli向我们提供了使用大多数所需配置来创建项目的命令。

npm install -g @vue/cli
vue create project-name

For the remaining things like BootstrapVue, vue-star-rating, etc, we can use the npm install command.

对于BootstrapVue,vue-star-rating等其余内容,我们可以使用npm install命令。

The default project created using vuecli has the following structure:

使用vuecli创建的默认项目具有以下结构:

/Root Folder 
 
 Public/

 src/
  
  assets/  /* Static assets like images goes here */
  components/ /* Small part of a view */
  views/  /* View represents a page composed of several components*/
  App.vue /* The main view inside which the routing logic goes */
  main.js  /* App initialisation happens here  */
  router.js /* Router logic is defined here */
  store.js /* Optional state management library Vuex */

 package.json /* It consist of all the dependencies of the project. */
 ......

The above things are there to explain the project architecture to you and the way to initialise it.

以上是向您解释项目架构以及初始化方式的内容。

We can get started by cloning the repository and writing the following commands:

我们可以通过克隆存储库并编写以下命令来开始使用:

npm install 
npm run serve

Some important components explained:

一些重要的组件进行了解释:

components/Header.vue

组件/Header.vue

The header has been created in the form of a single independent component so that it can be reused across pages, avoiding duplication of the code.

标头以单个独立组件的形式创建,因此可以在页面之间重用,从而避免了代码重复。

/* Vue style of writing component: template, script and style*/
<template>
  <div class="pad-15-hor pad-15-ver header">
    <div>
      <img src="@/assets/logo.png" width="25px"> Responsive Search
    </div>
    <div>
      <i class="fas fa-bars"></i>
    </div>
  </div>
</template>
<script>
export default {
  name: "Header"
};
</script>
<style scoped>
.header {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
</style>

components/Main.vue

组件/Main.vue

This component consist of the entire logic of search / filters and display of results fetched from the API.

此组件包含搜索/过滤器的整个逻辑以及从API提取的结果的显示。

This component is using the above Header by importing it in the script.

该组件通过将其导入脚本中来使用上述标题。

<template>
  <div>
    <Header/>
    <div class="pad-15-hor pad-15-ver search-parent">
      <div class="search-bar">
        <b-form-input
          @input="search_text()"
          v-model="search.text"
          type="text"
          placeholder="Search by Name"
        ></b-form-input>
        <span class="search-icon">
          <i class="fas fa-search"></i>
        </span>
      </div>
      <div>
        <span class="bold">Total Likes:</span>
        {{likes.count}}
        <span class="bold">Hits:</span>
        {{likes.hit}}
      </div>
      <div>
        <b-form-select @input="sort()" v-model="search.filter" :options="options"/>
      </div>
    </div>
<div class="container-fluid">
      <div class="row">
        <div class="col-md-6 pad-15-ver" v-for="wonder in wonders_data" :key="wonder.id">
          <div
            class="card-inner"
            @mouseover="show_hover(true,wonder.id)"
            @mouseout="show_hover(false,0)"
          >
            <img class="card-img" :src="wonder.imageURL">
<div class="card-bottom pad-15-hor" v-show="!hover_flag || active_id != wonder.id">
              <div class="min-width-160">
                <span class="bold">Ratings:</span>
                <star-rating
                  :rating="wonder.ratings"
                  :show-rating="false"
                  :inline="true"
                  :star-size="15"
                ></star-rating>
              </div>
              <div class="max-width-160">
                <span class="bold">{{wonder.place}}</span>
              </div>
            </div>
<div :class="{'card-hover':1}" v-show="hover_flag && active_id == wonder.id">
              <span
                @click="make_active(wonder.id)"
                :class="{'fas':1, 'fa-heart':1, 'absolute-star':1, 'green':check_active(wonder.id)}"
              >{{wonder.likes}}</span>
              <h5>{{wonder.place}}</h5>
              <p>{{wonder.description}}</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
/* Importing Header to use in this component */ 
import Header from "@/components/Header.vue";
/* Importing axios for async REST calls */
import axios from "axios";
export default {
  name: "Main",
/* mounted gets called when the component gets mounted. AJAX calls are preferred in mounted lifecycle method */
  mounted() {
    this.hover_flag = false;
var inside = this;
axios
      .get("https://www.mocky.io/v2/5c7b98562f0000c013e59f07")
      .then(function(response) {
        //console.log(response);
inside.wonders_data_actual = response.data.data;
response.data.data.map(function(wonder) {
          inside.likes.count += wonder.likes;
        });
inside.wonders_data_actual = inside.wonders_data_actual.map(function(
          wonder
        ) {
          wonder.active_like = false;
          return wonder;
        });
        inside.wonders_data = response.data.data;
      })
      .catch(function(error) {
        // console.log(error);
      });
  },
/* All the data variable declaration are done here:  */
  data() {
    return {
      hover_flag: false,
      wonders_data_actual: [],
      wonders_data: [],
      active_id: 0,
      options: [
        { value: null, text: "Sort By" },
        { value: "a", text: "Ratings" },
        { value: "b", text: "Likes" }
      ],
      search: { filter: null, text: "" },
      likes: { count: 0, hit: 0 }
    };
  },
/* Methods are defined here */
  methods: {
    show_hover(flag, active_id) {
      this.hover_flag = flag;
      this.active_id = active_id;
    },
    sort() {
      //console.log(this.search.filter);
      this.search.filter == "b"
        ? this.wonders_data.sort(function(a, b) {
            return b.likes - a.likes;
          })
        : this.wonders_data.sort(function(a, b) {
            return b.ratings - a.ratings;
          });
    },
    search_text() {
      //console.log(this.search.text);
var inside = this;
this.wonders_data = this.wonders_data_actual.filter(function(wonder) {
        if (
          wonder.place
            .toLowerCase()
            .indexOf(inside.search.text.toLowerCase()) != "-1"
        ) {
          return wonder;
        }
      });
    },
    check_active(id) {
      var flag = false;
      this.wonders_data_actual.map(function(wonder) {
        if (wonder.id == id) {
          flag = wonder.active_like;
        }
      });
      return flag;
    },
    make_active(id) {
      this.likes.hit++;
      this.wonders_data_actual = this.wonders_data_actual.map(function(wonder) {
        if (wonder.id == id) {
          wonder.active_like = !wonder.active_like;
          wonder.active_like ? wonder.likes++ : wonder.likes--;
        }
return wonder;
      });
      var inside = this;
inside.likes.count = 0;
      this.wonders_data_actual.map(function(wonder) {
        inside.likes.count += wonder.likes;
      });
    }
  },
  components: {
    Header
  }
};
</script>
<style scoped> /* Styles are scoped to this component only.*/
/* Style for Desktop/Tablet  */
.search-parent {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  background-color: lightgray;
}
.card-inner {
  position: relative;
  overflow: hidden;
  box-shadow: 2px 2px 8px grey;
}
.card-img {
  width: 100%;
}
.card-bottom {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 30px;
  width: 100%;
  background-color: white;
  opacity: 0.7;
  display: flex;
  justify-content: space-between;
}
.card-hover {
  position: absolute;
  right: 15px;
  left: 15px;
  top: 15px;
  bottom: 15px;
  background-color: white;
  opacity: 0.7;
  display: flex;
  flex-flow: column wrap;
  justify-content: center;
  align-items: center;
}
.absolute-star {
  position: absolute;
  top: 10px;
  right: 10px;
}
.card-hover p {
  font-size: 10px;
  text-align: center;
}
.bold {
  font-weight: 500;
}
.rating-div {
  width: 200px;
}
.search-bar {
  position: relative;
}
.search-bar input {
  padding-left: 30px;
}
.search-icon {
  position: absolute;
  top: 8px;
  left: 8px;
}
/* For Mobile Device, we will be going with column wrap approach */
@media screen and (max-width: 550px) {
  .search-parent {
    display: flex;
    flex-flow: column wrap;
    justify-content: center;
    align-items: center;
    background-color: lightgray;
  }
.search-parent div {
    width: 100%;
    text-align: center;
  }
}
</style>

I hope you have a better understanding of how to get started with Vue and create something awesome.

我希望您对如何开始使用Vue并创建很棒的东西有更好的了解。

If you found this helpful, clap below, give stars to the project repo and share with your friends too.

如果您觉得有帮助,请在下面一下,给项目回购加注 星号 ,并与您的朋友分享。

翻译自: https://www.freecodecamp.org/news/how-to-set-up-responsive-ui-search-in-vue-js-bf6007b7fc0f/

vue 响应式ui

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值