手记

用Vue.js实现一个简单的搜索框

在github上看到的练习,看个遍代码后自己再练一遍,先放原址:https://github.com/lavyun/vue-demo-search

主要用到的知识很简单,简单的vuejs2.0的知识就够了。源码用了.vue构建和ES6,用了webpack打包等等。我资历还浅,先用一个简单的.js的写。
先看效果

这里有两个组件,一个组件是logo部分的,一个是搜索框部分的。

html

html很简单,就是引用两个组件。

<div id="app">
    <logo-picture></logo-picture>
    <search-panel></search-panel>
</div>

//js还要实例#app
var app = new Vue({
    el: "#app"
})
logo

先来分析,首先一个<img />显示搜索引擎的图片,这里要响应式的,下面选择了不同的搜索引擎图标就要跟着换。所以<img :src="items[now].src" />。后面的倒三角点击时显示下拉列表<span @click="toggleFlag"> </span>
然后是下拉框。如果想要有过渡效果,那个就要包裹在<transition-group中,然后遍历li,记住元素要指定唯一的key。
想要有hover效果的话,用数据驱动的思维,就是比较index 与hoverindex是否相等,如果相等就加class。

Vue.component('logo-picture',{
    template :' \
    <div class="main-logo">\
        <img :src="items[now].src" @click="toggleFlag"/>\
        <span @click="toggleFlag" class="logoList-arrow"> </span>\
        <transition-group tag="ul" v-show="flagShow" class="logoList">\
            <li v-for="(item,index) in items" :key="index" @click="changeFlag(index)" @mouseover="flagHover(index)" :class="{selectback: index == hoverindex}">\
                <img :src="item.src" />\
            </li>\
        </transition>\
    </div>',
    data: function() {
        return {
            items: [{src:'../src/assets/360_logo.png'},{src:'../src/assets/baidu_logo.png'},{src:'../src/assets/sougou_logo.png'}],
            now: 0,
            flagShow: false,
            hoverindex: -1   
        }
    },
    methods: {
        //显示隐藏图片列表
        toggleFlag: function() {
            this.flagShow = !this.flagShow;
        },
        //改变搜索引擎
        changeFlag: function(index) {
            this.now = index;
            this.flagShow = false;
            bus.$emit("change",index);
        },
        //li hover
        flagHover: function(index) {
            this.hoverindex = index;
        }                     
    }
});
下拉框

input因为要双向绑定,所以要v-model="keyword",还要绑定键盘事件@keyup,如果按enter就搜索,向下向上就选中给定的返回信息列表。
下面的详情框与<logo-picture>下拉列表差不多。
搜索的话主要是运用$http.jsonp,还有ES6的语法?回掉好像是Promise的.then()。

Vue.component('search-panel',{
    template:'\
    <div class="search-input">\
        <input v-model="search" @keyup="get($event)" @keydown.enter="searchInput()" @keydown.down="selectDown()" @keydown.up.prevent="selectUp()"/>\
        <span @click="clearInput()" class="search-reset">&times;</span>\
        <button @click="searchInput()" class="search-btn">搜一下</button>\
        <div class="search-select">\
            <transition-group tag="ul" mode="out-in">\
                <li v-for="(value,index) in myData" :class="{selectback:index==now}" :key="index" @click="searchThis" @mouseover="selectHover(index)" class="search-select-option search-select-list">\
                    {{value}}\
                </li>\
            </transition-group>\
        </div>\
    </div>',
    data: function() {
        return {
            search: '',
            myData: [],
            flag: 0,
            now: -1,
            logoData: [
                {
                    'name': "360搜索",
                    searchSrc: "https://www.so.com/s?ie=utf-8&shb=1&src=360sou_newhome&q="
                },
                {
                    'name': "百度搜索",
                    searchSrc: "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd="
                },
                {
                    'name': "搜狗搜索",
                    searchSrc: "https://www.sogou.com/web?query="
                }
            ]
        }
    },
    methods: {
        get: function(event) {
            if(event.keyCode == 38 || event.keyCode == 40){  //向上向下
                return ;
            }
            this.$http.jsonp('https://sug.so.360.cn/suggest?word=' + this.search + '&encodein=utf-8&encodeout=utf-8').then(function(res) {
                this.myData = res.data.s;

            }, function() {

            });
        },
        //清除内容
        clearInput: function() {
            this.search = '';
            this.get();
        },
        //搜索
        searchInput: function() {
            alert(this.flag)
            window.open(this.logoData[this.flag].searchSrc+this.search);
        },
        //搜索的内容
        searchThis: function(index) {
            this.search = this.myData[index];
            this.searchInput();
        },
        //li hover
        selectHover: function(index) {
            this.search = this.myData[index];
            this.now = index;
        },
        //向下
        selectDown: function() {
            this.now++;
            if(this.now == this.myData.length) {
                this.now = 0;
            }
            this.search = this.myData[this.now];
        },
        //向上
        selectUp: function() {
            this.now--;
            if(this.now == -1) {
                this.now = this.myData.length - 1;
            }
            this.search = this.myData[this.now];
        }
    },
    created: function() {    //通信
        var self = this;
        bus.$on('change',function(index) {
            self.flag = index;
        })
    }
})
两个兄弟组件通信的问题

<logo-picture>换了搜索引擎的话,<search-panel>要换成相应的搜索引擎。这里要新建一个空的Vue对象做中间,因为两个组件不是父子关系。

var bus = new Vue();

//logo-picture里触发事件,并传递参数
bus.$emit("change",index);

//search-panel里监听事件是否发生
var self = this;
bus.$on('change',function(index) {
    self.flag = index;
})

这里要注意this问题,$on里this指向bus,所以要保存this才能引用search-panel.

5人推荐
随时随地看视频
慕课网APP

热门评论

github 的演示地址失效了


bucuo,nice

查看全部评论