Vue2.0組件實現動態搜索引擎(一)


 原文鏈接:https://blog.csdn.net/qwezxc24680/article/details/74550556

從github上看到一個不錯的開源項目:https://github.com/lavyun/vue-demo-search,

自己琢磨着不看代碼做了一遍學習了不少,現將碰到的坑與填坑過程分享出來。

 

首先看一下demo的界面:

 

簡單來說就是一個復刻各大搜索引擎的功能,用戶輸入關鍵字能出現搜索建議並上下鍵控制輸入框內容。

 

 

同時點擊上方logo能夠切換不同引擎,點擊搜一下能跳轉到對應網站搜索結果。

首先分析一下頁面,基本由2個部分組成:上方的LOGO部分和下方的輸入框與搜索建議彈框。

由於篇幅關系,這次先分析logo部分的實現代碼。

基於這次練習是針對Vue組件,所以我們可以將其拆分為logo組件和搜索組件,並將其設為父子組件方便初學,將來熟練以后可以考慮變為更常見的兄弟組件並使用event bus或者vuex來實現組件通信。

 

開發環境: Vue2.0、Node.js、npm、webpack、vue-cli、vue-resources、webstorm

 

為了以后項目工程化的目標,所以我們使用node+npm+webpack來構建項目。

准備工作包括安裝node,npm,然后依次安裝webpack,vue-cli

具體教程網上很多,就不在此贅述了。

 

1、選擇一個文件夾放工程,cmd進入該目錄

cd 目錄路徑(這里有個小坑,cd命令只對路徑當前盤符有效果,例如在c盤輸入d:../...是沒有效果的還要再輸入d:回車或者先進入d盤再cd 路徑)

 

2、創建項目

vue init webpack-simple 工程名字(不能使用中文)

會有一些初始化的設置,如下輸入:

Target directory exists. Continue? (Y/n)直接回車默認(然后會下載 vue2.0模板,慢的話連vpn)

Project name (vue-test)直接回車默認

Project description (A Vue.js project) 直接回車默認

 use sass?(Y/n)是否使用sass,選n回車

Author 寫你自己的名字

 

3、安裝項目依賴

npm install(npm服務器在國外可能會很慢,實在不行掛vpn)

 

4、啟動項目

npm run dev

正常的話默認瀏覽器就會打開頁面了,如圖:

 

 

這就是vue默認模板了,我們需要修改掉,開始建我們自己的項目。

首先修改src文件夾下的index.html:

 

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <title>Vue搜索</title>
  </head>
  <body>
      <div id="app1"></div>
  </body>
</html>

再到src下的main.js:        

 

 

import Vue from 'vue';
import App from './App1.vue';
var vueResource = require('vue-resource');
Vue.use(vueResource);

new Vue({
  el: '#app',
  render: h => h(App)
})

 

注意這里import App from ‘./App1.vue’對應項目vue文件,要使用vue resources也要在這里聲明。

然后在src下創建App1.vue:

 

<template>
  <div id="app">
      <panel></panel>
  </div>
</template>

<script>
  import panel from './components/panel-new.vue'

  export default {
    components: {
        panel
    }
  }
</script>

 

 

需要說明的是,vue文件一般來說由<template></template>、<script></script>、<style></style>組成,對應放html、js和css代碼。

這里出現第一個坑,就是template內只放一個div!

就算有並列的兄弟組件也還是要寫成:

<template>
<div>
<logo></logo>
<content></content>
<ending></ending>
</div>
</template>

而不能是:

<template>
<div>
<logo></logo>
</div>
<div>
<content></content>
</div>
<div>
<ending></ending>
</div>
</template>

否則會報錯。

引入組件后用export default導出到template中,此處有第二個bug:

千萬不要在單文件組件(.vue)中再次new Vue()!

因為已經在main.js中創建過實例了,重復的實例將會出現意外,詳情見我在seqement fault中的提問:

https://segmentfault.com/q/1010000009870708?_ea=2079044

 

接下來就是最關鍵的組件部分,在src下創建components文件夾,再新建logo-new.vue:

 

<template>
  <div class="logo">
    <img class="logoNow" :src="imgs[imgState].imgSrc" @click="toggle">
    <div class="triangle" @click="toggle">
      <span></span>
    </div>
    <div class="logoMain">
      <transition name="fade">
        <ul v-show="toggleState" class="listLogo" @mouseleave="leaveList">
          <li v-for="(item, index) in imgs" :class=" index == imgSelected ? 'colorBack' : ''" @click="changeImg(index)"
              @mouseover="changeBackColor(index)">
            <img :src="item.imgSrc">
          </li>
        </ul>
      </transition>
    </div>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        //下拉圖片背景初始值
        imgSelected: -1,
        //判斷下拉條件
        toggleState: false,
        //界面顯示哪張圖片
        imgState: 0,
        //圖片一類的靜態文件,應該放在這個static文件夾下,
        // 這個文件夾下的文件(夾)會按照原本的結構放在網站根目錄下
        imgs: [{
          imgSrc: ('.././static/360_logo.png')
        }, {
          imgSrc: ('.././static/baidu_logo.png')
        }, {
          imgSrc: ('.././static/sougou_logo.png')
        }]
      }
    },
    methods: {
      toggle: function () {
        this.toggleState = !this.toggleState,
        //清空上次背景色,
        this.imgSelected = -1
      },
      changeImg: function (index) {
        this.toggleState = !this.toggleState,
        this.imgState = index,
        this.$emit('logoNow', [index])
      },
      changeBackColor: function (index) {
        this.imgSelected = index
      },
      leaveList: function () {
          this.toggleState = false,
          this.imgSelected = -1
      }
    }
  }
</script>

<style>
  ul {
    padding: 0;
    margin: 0;
  }

  .logoMain {
    position: relative;
  }

  .listLogo {
    z-index: 9999;
    position: absolute;
    top: 50%;
    left: 60%;
    width: 200px;
    margin-left:-100px;
    /*border: 1px solid #fefefe;*/
  }

  li {
    background-color: #fefefe;
    list-style-type: none;
    width: 200px;
    margin-left: -50px;
  }

  /*li:hover {
    background-color: #ccc;
  }*/
  li img {
    cursor: pointer;
    width: 200px;
    height: 58.33px;
  }

  .logoNow, .triangle{
    cursor: pointer;
   }

  .triangle {
    display: inline-block;
    position: relative;
    left: -80px;
    top: -70px;
  }

  .triangle span {
    position: absolute;
    display: inline-block;
    width: 0;
    height: 0;
    border-width: 8px;
    border-color: #000 transparent transparent transparent;
    border-style: solid dashed dashed dashed;
  }

  .fade-enter-active, .fade-leave-active {
    transition: all .5s;
  }

  /* .fade-leave-active 在 <2.1.8 中 */
  .fade-enter, .fade-leave-to  {
    opacity: 0;
    -webkit-transform: translateY(20px);
    -moz-transform: translateY(20px);
    -ms-transform: translateY(20px);
    -o-transform: translateY(20px);
    transform: translateY(20px);
  }

  .colorBack {
    background-color: #ccc;
    cursor: pointer;
  }
</style>

 

 

說下整體思想:

點擊logo圖片可以彈出下拉框選擇3個不同的搜索引擎,再點擊選項替換logo的img src。

因為vue是以mvvc模式,任何操作都要與模型(數據)掛鈎,不能再用dom的思想;所以我們在data里給img設置一個數組,再由一個變量給定具體數值作為下標判斷其顯示狀態。至於下拉菜單部分可以設置為一個ul列表,再用v-show指令控制其顯示與否,同樣用一個布爾值變量toggleState來判斷,默認為false,一旦點擊logo圖片就會使其變為true,進而出現下拉菜單。

 

這里的重點在於如何將點擊的li與切換到對應logo圖片掛上鈎?

原生js的思想是用一個for循環,獲取到當前‘i’的值再去處理。Vue中也有類似的功能,在v-for循環中有一個參數‘index’可以表示當前索引,將其賦值給下標變量即可完成動態logo圖片切換。

 

另一個難點在於如何在列表li添加hover變色效果?

最簡單的方法自然是css中添加li:hover{background:#xxx},

但這顯然不是我們想要的方法,用了vue自然要利用其雙邊綁定的特性。

給li設置一個監聽mouseover的方法,將當前index賦值給一個變量,再用一個三元表達式綁定class即只要變量值與當前index相等,則添加一個帶背景色的class,否則class為空。

 

最后一個問題則是給下拉菜單添加過渡效果

vue封裝了css3的transition效果,只要在元素上添加name屬性,然后在style中用name-xxx指定參數即可,具體詳見官網https://cn.vuejs.org/v2/api/#transition

還有一個坑就是給多個元素/組件設置過渡效果就要使用transition-group標簽,像我們這個ul列表就是要的。

另外一個問題就是使用的時候一定要緊貼元素外層,不能中間隔了一個div,這樣是沒有效果的。

 

到此logo部分的組件大致完成,panel組件請留意我下一篇博文。

博主也是初學vue,並不精深,有出入的地方煩請各位看官指出!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM