整个panel组件分为3个部分:关键字输入框,相关搜索建议下拉列表和搜索跳转按钮。
由于我们整个项目是设计成父子组件的架构所以在父组件即panel部分开头需要引入子组件:
HTML:
import logoSelect from './logo-new.vue';
export default {
components: {
logoSelect //等价于logoSelect: logoSelect
}
目前的效果如下。
接下来做我们的搜索框,这一步比较简单,设置一个input再用v-model做一个双向绑定到data:
data: function () {
return {
msgInput: '',
...
}
}
x
methods: {
clearInput: function () {
this.msgInput = '',//清空输入框
this.results = ''//清空搜索建议数组
},
...
}
接下来就是核心功能:如何输入关键字就能自动弹出下拉菜单并且给出搜索建议?
由于我们要做的动态搜索建议,必然要使用其他搜索引擎的接口,那么跨域就成了主要技术难点。
翻阅了相关资料,使用jsonp跨域最为方便,Vue使用jsonp就要考虑vue-resource;
如果是第一次使用就要命令行安装:
npm install vue-resource --save
先在main.js引入vue-resource:
var vueResource = require('vue-resource');
Vue.use(vueResource);
然后我们在data里新建一个空数组以便将来存放jsonp获取到的搜索建议,之后便接着input标签写一个ul列表循环数组里的搜索结果。
-
{{ item }}
给input设置一个键盘监听事件,触发jsonp:
@keyup="get($event)"
methods: {
get: function (ev) {
//左右方向键不触发
if(ev.keyCode === 38 || ev.keyCode === 40) {
return;
}
//利用jsonp跨域
this.$http.jsonp('https://sug.so.360.cn/suggest?word=' + this.msgInput
+ '&encodein=utf-8&encodeout=utf-8')
.then(function(res) {//成功后执行函数
this.results = res.data.s//将搜索建议赋给预先准备好的数组
}
)
}
}
子组件向父组件传递信息一般是子组件$emit一个参数,父组件监听这个参数,再执行相应函数:
//监听的子组件函数不用写参数,但调用的函数需要加
changeSource: function (index) {
this.logoIndex = index
}
logoData: [
{
name: '360搜索',
url: 'https://www.so.com/s?ie=utf-8&fr=none&src=360sou_newhome&q='
},
{
name: '百度搜索',
url: 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd='
},
{
name: '搜狗搜索',
url: 'https://www.sogou.com/web?query='
}
search: function () {
window.open(this.logoData[this.logoIndex].url + this.msgInput)//进行字符串拼接url和搜索关键字
}
最后还有一个要点就是模仿主流搜索引擎的上下键选取搜索建议到输入框的功能。
@keydown.up.prevent="selectUp()" @keydown.down="selectDown()" @keydown.enter="search()"//prevent可以阻止input默认事件光标回到最前
selectDown: function () {
this.now++;//data中设置一个变量记录当前选中的index
if(this.now == this.results.length) {//到达最下回到顶部
this.now = 0;
}
this.msgInput = this.results[this.now];//改变输入框内容
},
selectUp: function () {
this.now--;
if(this.now == -1) {//到达最上回到底部
this.now = this.results.length - 1;
}
this.msgInput = this.results[this.now];
}
上面代码的核心原理跟之前的logo组件部分类似,也是先设置选中背景色,再通过对应index控制输入框的当前内容。
最后贴出完整代码:
main.js:
import Vue from 'vue';
import App from './App1.vue';
import VueRouter from 'vue-router';
var vueResource = require('vue-resource');
Vue.use(vueResource);
Vue.use(VueRouter);
new Vue({
el: '#app',
render: h => h(App)
})
App1.vue:
logo-new.vue:
-
panel-new.vue:
x
{{ item }}
逻辑功能的代码大致就是这样了,css部分大家可以结合自己喜好自行配置。