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