原文鏈接: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,並不精深,有出入的地方煩請各位看官指出!