很多伙伴在自己用vue学习开发的过程中,不像真正的工作开发,有后端支持,可以从后端那里调接口拿到真实的数据进行展示。但为了模拟这个过程,我们经常使用自己在本地编写模拟的数据进行使用,然后通过发送ajax请求得到我们本地的数据。
这次,超人鸭就使用本地编写的json数据,通过axios发送ajax请求,来获取本地数据,然后实现搜索功能,并在这个功能上加以拓展,实现搜索关键字的高亮。
//通过npm安装
npm install axios --save
//引入和挂载,在main.js里面
import axios from 'axios'
Vue.prototype.$axios = axios
//在组件中使用
this.$axios.get(url)
.then((res) => {
//成功的回调
})
上面是axios的基础用法,下面也会看到具体的使用
{
"data":{
"deviceList":[
{"name":"设备一","date":"2019-03-24","adress":"深圳","type":"电动"},
{"name":"设备二","date":"2019-03-24","adress":"上海","type":"汽油"},
{"name":"设备三","date":"2019-03-24","adress":"北京","type":"电动"},
{"name":"设备四","date":"2019-03-24","adress":"广州","type":"汽油"}
......
]
}
}
这就写好一个json文件,我们来看看在组件中如何通过axios调用到这个json文件:
//在组件的created钩子函数中调用
created(){
//写上文件的路径
this.$axios.get('../../../static/mock/device.json')
.then((res) => {
console.log(res)
})
}
看看打印出来的结果:
可以看到已经调用成功,我们要的数据在res.data.data.deviceList里面
先看看最终效果:
有一个输入框,当我输入 ‘设备’ 两个字后:
当我输入 ‘广州’ 两个字后:
可以看到完成了超人鸭所描述的效果,下面我将通过代码和代码中的注释来介绍功能的实现,样式部分就不写出来了,没什么影响。
<template>
<div class="bright-index">
<div class="search-box">
<input type="text" v-model="keyword" class="input" placeholder="请输入搜索内容, 提示:搜索设备">
<button class="btn" @click="search">搜索</button>
</div>
<div class="content-box">
<div class="content-card" v-for="(item ,index) in resultList" :key="index">
设备名称:<span v-html="item.name"></span>
<span>日期:<span v-html="item.date"></span></span>
<span>地址:<span v-html="item.adress"></span></span>
<span>类型:<span v-html="item.type"></span></span>
</div>
<h2 v-if="isShowTip">没有搜索到匹配结果</h2>
</div>
</div>
</template>
<script>
export default {
data () {
return {
keyword: '', //与输入框绑定的变量
deviceList: [], // 调用json文件获取的全部数据
resultList: [], //真正展示的数据,也就是筛选后的数据
isShowTip: false //当搜索不到数据时为true
}
}
</script>
//首先得到数据,在created里面使用axios
created() {
this.$axios.get('../../../static/mock/device.json')
.then((res) => {
//将json文件中的数据赋值给data里面的deviceList
this.deviceList = res.data.data.deviceList
})
}
//然后我们给按钮绑定了一个点击事件search,在这个事件中做处理
methods:{
search() {
if (this.keyword == '') { //如果没有输入内容,不让往下执行
return
}
this.resultList = [] //每次搜索对结果数组做初始化
this.deviceList.forEach((item) => { //把初始数据进行遍历
/**
下面是把初始数据中的每一条数据的四个字段分别去和输入的内容进行匹配,
如果某一字段中包含输入的内容,就往resultList中加
**/
if (item.name.indexOf(this.keyword) > -1 ||
item.date.indexOf(this.keyword) > -1 ||
item.adress.indexOf(this.keyword) > -1 ||
item.type.indexOf(this.keyword) > -1) {
this.resultList.push(item)
}
})
if (this.resultList.length == 0) { //如果没有匹配结果,就显示提示信息
this.isShowTip = true
}
}
}
//将得到的每一条数据中的每一个字段进行处理,brightKeyword就是变高亮的方法
this.resultList.map((item) => { //遍历
item.name = this.brightKeyword(item.name)
item.date = this.brightKeyword(item.date)
item.adress = this.brightKeyword(item.adress)
item.type = this.brightKeyword(item.type)
}) //到这里search方法结束
---------------------------------
brightKeyword(val) {
let keyword = this.keyword //获取输入框输入的内容
if (val.indexOf(keyword) !== -1) { //判断这个字段中是否包含keyword
//如果包含的话,就把这个字段中的那一部分进行替换成html字符
return val.replace(keyword, `${keyword}`)
} else {
return val
}
}
将每一个字段都进行一次处理,来实现关键字高亮的效果。
-备注 如果是搜索两个关键字,按空格区分的话
brightenKeyword (val) {
val = val + ''
let keyword = this.keyword
var arr = keyword.split(' ') // 为了多字段高亮,把字符串按空格分为数组
for (let i = 0; i < arr.length; i++) {
// 遍历数组
if (val.indexOf(arr[i]) !== -1 && val !== '') {
val = val.replace(
// 进行替换,替换返回新结果,但原字符串不会受影响
arr[i],
'' + arr[i] + ''
// `${arr[i]}` es6写法
)
}
}
return val
},
let obj1 = { foo: 1 }
let obj2 = obj1
obj2.foo = 3
console.log(obj1.foo) //打印出来之后是3
这就是对象的浅拷贝,数组也会出现这种情况。这是因为js中对象和数组是引用数据类型,存储方式和基本数据类型(字符串、数字等)不一样,直接赋值给另一个对象的话,另一个对象改变属性自己的属性也会跟着改变。(如果这块不明白的话,可以先知道这么一回事就好,等超人鸭再出一篇详细介绍js存储对象的方式)
search() {
this.$axios.get('../../../static/mock/device.json')
.then((res) => {
//将json文件中的数据赋值给data里面的deviceList
this.deviceList = res.data.data.deviceList
})
....
}
看起来似乎没问题了?
熟悉axios插件的伙伴都知道,axios是用promise封装的,而promise是用来处理异步操作的。异步就是不能确定它什么时候能执行完的操作,所以这样写的话,不能确定它是什么时候执行完成,所以不能确定deviceList什么时候才能获取到数据,当方法继续往后走而deviceList 没有数据就会报错。
promise支持这样的写法:
search() {
this.$axios.get('../../../static/mock/device.json')
.then((res) => {
//将json文件中的数据赋值给data里面的deviceList
this.deviceList = res.data.data.deviceList
}).then(() => {
//把上面search写的代码放在这里面
})
}
到这里就完成了,确保了每次都是获取新的数据而且在获取数据成功后才执行下一步操作。实现了用模拟数据进行搜索,关键字高亮的效果。下面超人鸭放上完整代码,不足的地方请大家多多指教。
<template>
<div class="bright-index">
<div class="search-box">
<input type="text" v-model="keyword" class="input" placeholder="请输入搜索内容, 提示:搜索设备">
<button class="btn" @click="search">搜索</button>
</div>
<div class="content-box">
<div class="content-card" v-for="(item ,index) in resultList" :key="index">
设备名称:<span v-html="item.name" style="color:#000;"></span>
<span>日期:<span v-html="item.date"></span></span>
<span>地址:<span v-html="item.adress"></span></span>
<span>类型:<span v-html="item.type"></span></span>
</div>
<h2 v-if="isShowTip">没有搜索到匹配结果</h2>
</div>
</div>
</template>
<script>
export default {
data () {
return {
keyword: '',
deviceList: [],
resultList: [],
isShowTip: false
}
},
methods: {
search () {
this.isShowTip = false
if (this.keyword == '') {
this.$message.warning('请输入搜索内容')
return
}
this.$axios.get('../../../static/mock/device.json')
.then((res) => {
this.deviceList = res.data.data.deviceList
}).then(() => {
this.resultList = []
this.deviceList.forEach((item) => {
if (item.name.indexOf(this.keyword) > -1 ||
item.date.indexOf(this.keyword) > -1 ||
item.adress.indexOf(this.keyword) > -1 ||
item.type.indexOf(this.keyword) > -1) {
this.resultList.push(item)
}
})
if (this.resultList.length == 0) {
this.isShowTip = true
}
this.resultList.map((item) => {
item.name = this.brightKeyword(item.name)
item.date = this.brightKeyword(item.date)
item.adress = this.brightKeyword(item.adress)
item.type = this.brightKeyword(item.type)
})
})
},
brightKeyword (val) {
let keyword = this.keyword
if (val.indexOf(keyword) !== -1) {
return val.replace(keyword, `${keyword}`)
} else {
return val
}
}
}
}
</script>