1. 程式人生 > >VUE:vue 搜尋結果高亮顯示關鍵字(父+子)

VUE:vue 搜尋結果高亮顯示關鍵字(父+子)

1. 需要解決的問題

  • 父元件將搜尋的欄位傳到子元件
  • 子元件接受資料,正則匹配,並替換欄位

2. 具體程式碼

  1. 父元件程式碼
<template>
  <div>
  <div v-if="showMe">
    <div class="re_search">
      <svg @click="$router.go(-1)">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#arrow-left.6f6409e"></use>
      </svg>
      <input type="search" v-model="search_text" class="v-md" placeholder="請輸入商品名稱" @keydown.enter="search_method">
    </div>
    <OneBusiness v-for="(item, n) in search_res" :key="n" :item="item" :search_text="search_text"></OneBusiness>
  </div>
    <!--&lt;!&ndash; 撐開Fixednav擋住的位置 &ndash;&gt;-->
    <div class="space"></div>
    <!-- 固定導航欄 -->
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
import OneBusiness from './small_components/One_business';
import {getSearchData} from 'src/service/getData'


export default {
  name: 'search',
  data () {
    return {
      showMe: false,
      search_text: '', // 搜尋框內容
      search_res: [] // 搜尋結果
    };
  },
  mounted () {
    this.$store.dispatch('setLoading', true);
    // 模擬載入
    var time = Math.floor(Math.random() * 2000);
    console.log('模擬載入用時' + time);
    setTimeout(() => {
      this.$store.dispatch('setLoading', false);
      this.showMe = true;
    }, time);
    this.search_method();
  },
  computed: {
    ...mapGetters([
      'getFalseBussinessbrief' // 商家簡略資訊
    ])
  },
  methods: {
    async search_method () {

      var mainWord = this.$route.params.keyword;
      if (this.search_text !== '' && this.search_text !== this.$route.params.keyword) {
        mainWord = this.search_text;
      }
      this.search_text = mainWord;
      this.search_res = (await getSearchData(this.search_text)).obj.results;
      console.log(this.search_res);
    }
  },
  components: {
    OneBusiness
  }
};
</script>

<style lang="less" scoped>
.re_search{
  background:#0096ff;
  line-height:0;
  padding: .2rem;
  svg{
    width:.6rem;
    height:.6rem;
  }
  input[type="search"]{
    display:inline-block;
    height:.9rem;
    width:8rem;
    outline: none;
    border: none;
    border-radius:.45rem;
    background:#f2f2f2;
    box-sizing: border-box;
    padding: 0 .5rem;
    font-size:.4rem;
  }
}
</style>

  1. 子元件程式碼
<template>
  <!-- 列表單個商家 -->
  <section class="tj_business"  >
    <section class="one_business clear">
      <div class="business_img">
        <img src="../../images/guozhao.png" alt="">
      </div>
      <div class="business_info">
        <section class="business_name clear">
          <router-link :to="'/business/' + item.classNum">
            <h3 class="fl ell"><span v-if="item.className">大類</span>第{{item.classNum}}類{{ item.className }}</h3>
          </router-link>
          <div class="name_icon fr">
            <div class="code_num fr">
              <svg @click="add_cart(item.id)" style="    width: .5rem; height: .5rem;">
                <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-minus"></use>
              </svg>
            </div>
          </div>
        </section>
        <section class="business_code clear">
          <div class="code_num fl">
            <!--<svg class="v-md">-->
              <!--<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#rating-star"></use>-->
            <!--</svg>-->
            <span class="v-md">【{{item.parentNum}}組】{{ item.groupName }}</span>
          </div>
          <div class="code_icon fr">
          </div>
        </section>
        <section class="business_other clear">
          <div class="other_price fl">
            <span class="com_gray1" v-html="ruleTitle"></span>
            <span>/</span>
            <span class="com_gray1">{{ item.number }}</span>
          </div>
          <div class="other_dis fr">
          </div>
        </section>
      </div>
    </section>

  </section>

</template>

<script>
  import {
    addMyshopcart,
  } from 'src/service/getData'

  export default {
    name: 'one_business',
    props: {
      search_text:String,
      item:{}
    },
    data () {
      return {
        msg: '1'

      };
    },
    mounted () {

    },
    computed: {
      isLogin () {
        return this.$store.getters.getLogin;
      },
      ruleTitle() {
        let titleString = this.item.gname;
        if (!titleString) {
          return '';
        }
        if (this.search_text && this.search_text.length > 0) {
          // 匹配關鍵字正則
          let replaceReg = new RegExp(this.search_text, 'g');
          // 高亮替換v-html值
          let replaceString = '<span class="search-text">' + this.search_text + '</span>';
          // 開始替換
          titleString = titleString.replace(replaceReg, replaceString);
        }
        return titleString;
      }
  },
    methods: {
      async add_cart(id){
        if (!this.isLogin) {
          this.$router.replace('/login');
        } else {
          var userId = this.$store.getters.getuname;
          var result = await addMyshopcart(id, userId)
          console.log(result.resMsg)

          if (result.res === 1) {
            this.$router.replace('/ShopCart/' + userId);
          } else {
            alert(result.resMsg)
          }
        }
      }
    }

  };
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="less">
  @baseBlue: #0096ff;
  @com_gray1: #666;
  @com_gray2: #999;
.search-text{
  color: #52250a;
  background: #ffd930;
  font-size: .2rem;
  padding: .02rem;
  border-radius: 2px;
  vertical-align: top;
  margin-right: .04rem;
}


  .com_gray1 {
    color: @com_gray1;
  }

  .com_gray2 {
    color: @com_gray2;
  }

  .com_blue {
    color: @baseBlue;
  }

  /* 單個商家 */
  .one_business {
    background: #fff;

    .business_img {
      width: 1.6rem;
      height: 1.6rem;
      padding: 0.4rem;
      float: left;
      img {
        width: 100%;
        height: 100%;
      }
    }
    .business_info {
      float: right;
      width: 7.4rem;
      height: 1.6rem;
      padding: 0.4rem .2rem .4rem 0;
      .business_name {
        font-size: .35rem;
        line-height: .45rem;
        vertical-align: top;
        h3 {
          width: 5rem;
          display: inline-block;
          /*span {*/
            /*color: #52250a;*/
            /*background: #ffd930;*/
            /*font-size: .2rem;*/
            /*padding: .02rem;*/
            /*border-radius: 2px;*/
            /*vertical-align: top;*/
            /*margin-right: .04rem;*/
          /*}*/
        }
        .bzp {
          width: .3rem;
          height: .3rem;
          font-size: .26rem;
          text-align: center;
          line-height: .3rem;
          display: inline-block;
          color: @com_gray2;
          border: 0.01rem solid #ddd;
          padding: 0.01rem;
          border-radius: 3px;
          i {
            font-style: normal;
          }

        }
      }
      .business_code, .business_other {
        font-size: .25rem;
        margin-top: .3rem;
        line-height: .25rem;
      }

    }
    .code_num {
      svg {
        width: .3rem;
        height: .3rem;
        fill: #ffaa0c;
      }
    }
    .zsd {
      font-size: .25rem;
      height: .35rem;
      line-height: .3rem;
      padding: 0 0.05rem;
      display: inline-block;
      color: @baseBlue;
      background: #fff;
      border: 0.01rem solid @baseBlue;
      box-sizing: border-box;
      border-radius: 3px;
    }
    .fnzs {
      font-size: .25rem;
      height: .35rem;
      padding: 0 0.05rem;
      line-height: .3rem;
      display: inline-block;
      background: @baseBlue;
      color: #fff;
      border: 0.01rem solid @baseBlue;
      box-sizing: border-box;
      border-radius: 3px;
    }
  }
</style>