Интерактивный матчер с помощью vuejs

Когда вы устраиваетесь на новую работу в качестве front-end разработчика, вы можете получить любой тип интервью и некоторые задания с того или иного уровня процесса интервью. В настоящее время у нас есть 2 вида задач «многие популярные тестовые (интервью) задачи» и «не популярные тестовые задачи» для frontend разработчиков.BTW многие компании считают, что тестовые задачи от их компаний уникальны, и они просят, чтобы вы (кандидат) держали их в секрете и не публиковали в публичном GitHub repo. Но когда вы ищете ключевые слова задачи, во многих случаях вы можете найти полные публичные проекты GitHub с той же задачей с тем же API… и так далее. Давайте решим эту задачу интерактивным матчером из задач интервью с помощью vuejs, и вы сможете найти полный проект из этого публичного GitHub репо.
Мы создадим новый проект vuejs, внутри этого проекта мы создадим папку assets с 2 cvs файлами 1 это «sound_recordings.cvs» 2 это «sound_recordings_input_report.cvs».
Для работы с управлением состоянием мы создадим store.js в папке src проекта и добавим код, приведенный ниже:

import Vue from "vue";
import Vuex from "vuex";
import recordingsdata from "./assets/sound_recordings.csv";

import inputsdata from "./assets/sound_recordings_input_report.csv";
Vue.use(Vuex);

const appendId = (tempArray) => {
  return tempArray.map((item) => ({
    id: Math.random().toString().slice(2),
    ...item,
  }));
};

const postRecordingsData = appendId(recordingsdata);
const postInputs = appendId(inputsdata);

export const store = new Vuex.Store({
  state: {
    // origin
    recordings: postRecordingsData,

    // left aside list
    inputs: postInputs,

    // right aside list
    results: postRecordingsData,

    selectedInputsItem: {},
    selectedResultsItem: {},
  },
  mutations: {
    SET_STATE(state, payload) {
      Object.keys(payload).forEach((key) => {
        if (key in state) {
          state[key] = payload[key];
        }
      });
    },
    S_INPUT(state, payload) {
      state.selectedInputsItem = payload;
    },
    addInput(state) {
        console.log("state.selectedInputsItem:", state.selectedInputsItem);
    state.recordings.push(state.selectedInputsItem.item);
    state.results.push(state.selectedInputsItem.item)
    console.log("state:",state);    
    },
  },
});

Вход в полноэкранный режим Выйти из полноэкранного режима

и внутри файла App.vue добавим код ниже:

<template>
  <div id="app">
    <Header />
    <div class="container">
      <div class="row">
        <div class="col-md-5">
          <Inputs />
        </div>
        <div class="col-md-2">
          <Actions />
        </div>
        <div class="col-md-5">
          <Database />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Header from "./components/Header.vue";
import Inputs from "./components/inputs/Inputs.vue";
import Actions from "./components/actions/Actions.vue";
import Database from "./components/database/Database.vue";

export default {
  name: "App",
  components: {

    Header,
    Inputs,
    Actions,
    Database,
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #181c20;
  /* margin-top: 60px; */
}
</style>

Вход в полноэкранный режим Выйти из полноэкранного режима

В папке компонентов мы создадим компоненты Inputs, Database и Actions, Actions добавим код ниже:

<template>
 <div>
  <button class="btn btn-outline-primary" @click="register"><i class="fa fa-arrow-right"></i> Register</button>
  </div>
</template>
<style scoped>
</style>
<script>

import { mapMutations } from "vuex";
export default {

  methods: {
    ...mapMutations(["SET_STATE"]),

    register() {
      console.log("selected:----",this.$store.state.selectedInputsItem);
      this.$store.commit('addInput')

    },
  },
};
</script>
Вход в полноэкранный режим Выйти из полноэкранного режима

Для компонента Database код выглядит следующим образом:

<template>
  <div>
    <input type="text" v-model="search" placeholder="Search title.." />

    <div>Records: {{ recordings.length }}</div>
    <ul class="list-group list-group-flush">
      <li class="mt-4" v-for="item in recordings" :key="item.id">
        <div class="card">
          <div class="card-body">
            <h5 style="">{{ item.title }}</h5>
            <p>{{ item.artist }}</p>
            <div style="display: flex; justify-content: space-between">
              <h6>{{ item.isrc }}</h6>
              <h6>{{ item.duration | formatTime }}</h6>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      search: "",
    };
  },
  computed: {
    recordings() {
      const searchrg=new RegExp(this.search,'i');
      return this.$store.state.results.filter((item) =>
        [item.isrc, item.artist, item.title].some((el) =>
          el && el.toLowerCase().match(searchrg)
        )
      );
    },
  },

  filters: {
    formatTime(time) {
      if (time > 0) {
        var mins = ~~((time % 3600) / 60);
        var secs = ~~time % 60;

        var ret = "";
        ret += "0" + mins + "m" + " " + (secs < 10 ? "0" : "");
        ret += "" + secs + "s";
        return ret;
      } else return "";
    },
  },
  methods: {

};
</script>
<style scoped>
ul {
  list-style-type: none;
  overflow: scroll;
  overflow-x: hidden;
  height: 80vh;
}
</style>
Войти в полноэкранный режим Выйти из полноэкранного режима

Наконец, для ввода добавьте код ниже:

<template>
  <ul class="list-group list-group-flush">
    <div>Inputs: {{ inputs.length }}</div>
    <li class="mt-4" v-for="item in inputs" :key="item.id">
      <div class="card " v-bind:class="{isActive:activeItem===item}" @click="findMatch(item)">
        <div class="card-body">
          <h5 style="">{{ item.title }}</h5>
          <p>{{ item.artist }}</p>
          <div style="display: flex; justify-content: space-between">
            <h6>{{ item.isrc }}</h6>
            <h6>{{ item.duration | formatTime }}</h6>
          </div>
        </div>
      </div>
    </li>
  </ul>
</template>
<style scoped>
ul {
  list-style-type: none;
  overflow: scroll;
  overflow-x: hidden;
  height: 80vh;
}
.isActive{
  border:18px solid #e19eae ;
}
</style>
<script>
import { mapMutations } from "vuex";
export default {
  data() {
    return {
      activeItem:null
    };
  },
  computed: {
    inputs() {
      return this.$store.state.inputs;
    },
  },
  methods: {
    ...mapMutations(["SET_STATE","S_INPUT"]),

    findMatch(item) {
      console.log(item);
      this.activeItem=item;
     this.S_INPUT({item});


      const targetFields =(item.title.toUpperCase()+' '+item.artist.toUpperCase() +(item.isrc?' ' + item.isrc?.toUpperCase():'')).split(' ');


      const t = this.$store.state.recordings.filter((elem) => {
         const ele=(elem.title.toUpperCase()+' '+elem.artist.toUpperCase() +' '+elem.isrc?.toUpperCase()).split(' ');

         return ele.filter(field=> targetFields.includes(field)).length>0;



      this.SET_STATE({
        results: t || [],
      });

    },
  },
  filters: {
    formatTime(time) {
      if (time > 0) {
        var mins = ~~((time % 3600) / 60);
        var secs = ~~time % 60;

        var ret = "";
        ret += "0" + mins + "m" + " " + (secs < 10 ? "0" : "");
        ret += "" + secs + "s";
        return ret;
      } else return "";
    },
  },
};
</script>
Войти в полноэкранный режим Выйти из полноэкранного режима

Когда вы запустите проект, вы сможете увидеть его на изображении вкладки браузера ниже.

Надеюсь, эта статья поможет вам пройти собеседование.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *