vueベースのリアルタイム検索で、結果にキーワードをハイライト表示
参考資料:【Vue.js】vueのリアルタイム検索に基づき、結果にキーワードをハイライト表示https://www.cnblogs.com/pengshengguang/p/8059190.htmlJS大文字と小文字を区別しない文字列ハイライトシミュレーションブラウザCtrl+Fhttps://www.jianshu.com/p/936029d3b9a6jsエスケープと逆エスケープhtmlhttps://www.cnblogs.com/daysme/p/7100553.htmlJavascript(js)によるHTMLエスケープツール(特殊文字表示の処理)https://blog.csdn.net/hj7jay/article/details/51280405axiosインタフェースリクエストのキャンセルhttps://www.jianshu.com/p/22b49e6ad819
<template>
<div class="awc-search">
<div class="awcs-wrap">
<div class="awcs-shade">div>
<div class="awcs-inner">
<input
type="text"
placeholder=" / "
class="awcsi-input"
v-model="searchVal"
@keyup.enter="searchSkip()"
@keyup.delete="searchDel()"
@input="searchInput()"
@click="searchInput()"
@keyup.up="upKey()"
@keyup.down="downKey()"
@blur="searchBlur()"
/>
<div class="awcsi-icon-wrap" @click="searchSkip()">
<i class="awcsi-icon">i>
div>
<div class="search-list" v-if="sugShow">
<div
class="sl-item"
v-for="(val,index) in sugList"
:key="index"
:checkVal="val.value"
v-html="val.span"
@click="itemClick(val.value)"
@mouseover="sugOver($event,index)"
@mouseout="sugOut($event,index)"
>div>
div>
div>
div>
div>
template>
<script>
// ( : , js, js,json , )
// :import 《 》 from '《 》';
// api axios
import { Api } from "@/config/api";
import axios from "@/config/axios.js";
import {
encodeHtml,
decodeHtml,
html_encode,
html_decode
} from "@/config/js-string";
import { setTimeout } from "timers";
export default {
//import
components: {},
data() {
//
return {
searchVal: "",
//
sugShow: false,
sugList: [],
sugIndex: -1,
sugTime: null,
srfFlag: true, //
// cancel:null, //
blurOrclick: true, //
isIeAxios:true, // ie js input val oninput
};
},
//
props: ["searchType"],
// data
computed: {},
// data
watch: {
searchVal() {
const that = this;
// console.log(encodeHtml(' '),'encodeHtml'); // < > encodeHtml
// console.log(decodeHtml(' '),'decodeHtml'); // < > decodeHtml
// console.log(html_encode(' '),'html_encode'); // < > html_encode
// console.log(html_decode(' '),'html_decode'); // html_decode
//
that.searchVal = html_decode(that.searchVal);
// if( that.searchVal == '' ){
// if (that.searchType == "artworkclassify") {
// console.log(' ',that.searchType,that.searchVal)
// that.$emit("searchBackVal",'');
// that.sugShow = false;
// }
// }
}
},
//
methods: {
//
searchSkip() {
const that = this;
console.log(that.searchVal, that.searchType);
if (!that.searchVal) {
this.$message.closeAll();
that.$message.error(" ");
return false;
}
that.clearData();
//
if (that.searchType == "artworkclassify") {
that.$emit("searchBackVal", that.searchVal);
} else {
that.$emit("searchBackVal", that.searchVal);
that.$router.push({
name: "artworkclassify",
params: {
searchType: that.searchType,
searchVal: that.searchVal
}
});
that.searchVal = "";
}
},
//
clearData() {
const that = this;
that.sugList = [];
that.sugShow = false;
that.sugIndex = -1;
},
//
searchDel() {
const that = this;
console.log(" ", that.searchType, that.searchVal);
setTimeout(() => {
if (that.searchVal == "") {
if (that.searchType == "artworkclassify") {
console.log(" ", that.searchType, that.searchVal);
that.$emit("searchBackVal", "-asjsaljkfjsla");
that.sugShow = false;
}
}
}, 100);
},
//
searchBlur() {
const that = this;
setTimeout(() => {
if (that.blurOrclick) {
setTimeout(() => {
that.$emit("searchBackVal", that.searchVal);
that.sugShow = false;
}, 300);
}
}, 0);
},
//
searchInput: function(e) {
var that = this;
// ie
if( !that.isIeAxios ){
that.isIeAxios = true;
return;
}
that.itemClassDel();
if (that.searchVal.trim() == "") {
that.clearData();
return;
}
//
let searchApiConfig = {
headers: {
loadingFalse: true
}
};
clearTimeout(that.sugTime);
that.sugTime = setTimeout(() => {
if (that.srfFlag) {
if (that.cancel) {
//
that.cancel("canceled by user");
}
let CancelToken = axios.CancelToken;
that.axios
.get(
`/artwork/search_suggest/?keywords=${encodeURI(that.searchVal)}`,
searchApiConfig,
{
cancelToken: new CancelToken(function executor(c) {
self.cancel = c;
// c CancelToken ,
})
}
)
.then(res => {
if (res.data.code == 2001) {
that.sugList = [];
that.sugIndex = -1;
// that.sugList = res.data.data.data_list;
that.sugList = that.spanColor(
that.searchVal,
res.data.data.data_list
);
that.sugShow = true;
} else {
that.clearData();
}
})
.catch(err => {
that.clearData();
});
}
}, 0);
},
// item
itemClassDel() {
const that = this;
let objList = document.querySelectorAll(".sl-item");
for (let i = 0; i < objList.length; i++) {
objList[i].classList.remove("sl-active");
objList[i].classList.remove("overitem");
}
},
//
itemClick(val) {
const that = this;
that.searchVal = val;
that.blurOrclick = false;
setTimeout(() => {
that.searchSkip();
that.blurOrclick = true;
}, 200);
},
//
spanDel(str) {
let newstr = str.replace(/]+>/g, "");
return newstr;
},
//
spanColor(searchValue, data) {
let comData = [];
searchValue = html_decode(searchValue);
//
let YesStrReg = new RegExp(
/[(\@)(\#)(\$)(\^)(\&)(\*)(\[)(\])(\{)(\})(\|)(\\)(\')(\/)(\)(\《)(\》)(\)]+/
);
let searchValueYesStr = searchValue.replace(
/[(\@)(\#)(\$)(\^)(\&)(\*)(\[)(\])(\{)(\})(\|)(\\)(\')(\/)(\)(\《)(\》)(\)]+/g,
""
);
let zimuReg = new RegExp(/[A-Za-z]/);
for (let val of data) {
if (!val) {
return "";
}
val = html_decode(val);
let obj = {
span: "",
value: val
};
if (searchValue && searchValue.length > 0) {
console.log(YesStrReg.test(searchValue),'dsakjjkasdjkasjk')
//
if (zimuReg.test(searchValue)) {
console.log(val, searchValue, " ");
//
let placeVal = searchValue.replace(/(^\s*)|(\s*$)/g, "");
let zimuPlace = new RegExp(placeVal, "gi");
var replaceString = str => `${str}`;
obj.span = val.replace(zimuPlace, function(num) {
return replaceString(num);
});
} else {
//
if (YesStrReg.test(val)) {
// console.log(val, searchValue, " ");
//
let replaceReg = new RegExp(searchValue, "g");
// v-html
let replaceString =
'' +
searchValue +
"";
//
obj.span = val.replace(replaceReg, replaceString);
} else {
// console.log(val, searchValue, " ");
//
//
let replaceReg = new RegExp(searchValueYesStr, "g");
// v-html
let replaceString =
'' +
searchValueYesStr +
"";
//
obj.span = val.replace(replaceReg, replaceString);
}
}
}
// span <> bug
obj.span = html_encode(obj.span);
obj.span = obj.span.replace(/<span class="search-text" style="color:#5890EB;">/gi,``);
obj.span = obj.span.replace(/<\/span>/gi,``);
comData.push(obj);
}
return comData;
},
//
downKey: function() {
const that = this;
if (that.sugList.length > 0) {
if (that.sugIndex < that.sugList.length - 1) {
that.sugIndex += 1;
}
}
that.itemClassDel();
let objList = document.querySelectorAll(".sl-item");
if (objList.length > 0) {
objList[that.sugIndex].classList.add("sl-active");
that.searchVal = objList[that.sugIndex].getAttribute("checkVal");
}
},
//
upKey: function() {
const that = this;
if (that.sugList.length > 0) {
if (that.sugIndex > 0) {
that.sugIndex -= 1;
}
}
that.itemClassDel();
let objList = document.querySelectorAll(".sl-item");
if (objList.length > 0) {
objList[that.sugIndex].classList.add("sl-active");
that.searchVal = objList[that.sugIndex].getAttribute("checkVal");
}
},
sugOver(event, i) {
const that = this;
let obj = event.currentTarget;
that.itemClassDel();
obj.classList.add("overitem");
that.sugIndex = i;
},
sugOut(event, i) {
const that = this;
let obj = event.currentTarget;
that.itemClassDel();
obj.classList.remove("overitem");
that.sugIndex = -1;
}
},
// - ( this )
created() {},
// - ( DOM )
mounted() {
const that = this;
// ,compositionstart 、 compositionend 、 input
let srkInputObj = document.getElementsByClassName("awcsi-input")[0];
srkInputObj.addEventListener("compositionstart", function(data) {
//
that.srfFlag = false;
});
srkInputObj.addEventListener("compositionend", function(data) {
//
that.srfFlag = true;
});
//
if (that.$route.params.searchVal) {
that.searchVal = that.$route.params.searchVal;
if(!!window.ActiveXObject || "ActiveXObject" in window){
that.isIeAxios = false;
console.log(' ie edeg');
// return true;
}else{
console.log(' ie ');
// return false;
}
}
},
beforeCreate() {}, // -
beforeMount() {}, // -
beforeUpdate() {}, // -
updated() {}, // -
beforeDestroy() {}, // -
destroyed() {}, // -
activated() {} // keep-alive ,
};
script>
<style lang='less' scoped>
//@import url(); css
.visibility {
visibility: hidden;
}
.awcs-wrap {
height: 216px;
background: url("./images/asearch-bg.png") no-repeat;
background-size: cover;
position: relative;
}
.awcs-shade {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(37, 79, 113, 0.2);
}
.awcs-inner {
position: absolute;
left: 50%;
margin-left: -374px;
top: 50%;
margin-top: -29px;
z-index: 100;
.awcsi-input {
width: 748px;
height: 58px;
padding: 18px;
padding-right: 70px;
border: none;
letter-spacing: 1px;
box-sizing: border-box;
font-size: 16px;
color: #222222;
}
.awcsi-icon-wrap {
width: 30px;
height: 30px;
padding: 14px 20px;
position: absolute;
top: 0;
right: 0;
cursor: pointer;
.awcsi-icon {
width: 100%;
height: 100%;
display: block;
background: url("./images/asearch-icon.png") no-repeat;
background-size: cover;
}
}
}
.search-list {
border-top: 1px solid #f2f2f2;
padding: 10px 0;
background: #fff;
z-index: 10;
}
.sl-item {
text-align: left;
line-height: 30px;
color: #888888;
font-size: 16px;
cursor: pointer;
padding: 0 20px;
}
.overitem:hover {
background: #fafafa;
background: rgba(34, 34, 34, 0.2);
}
.sl-item.sl-active {
background: #fafafa;
background: rgba(34, 34, 34, 0.2);
}
style>
// js-string.js
// ---- ---
// https://www.cnblogs.com/daysme/p/7100553.html
// console.log(encodeHtml(' '),'encodeHtml'); // < > encodeHtml
// console.log(decodeHtml(' '),'decodeHtml'); // < > decodeHtml
// console.log(html_encode(' '),'html_encode'); // < > html_encode
// console.log(html_decode(' '),'html_decode'); // html_decode
export const html_encode = (str) =>
{
var s = "";
if (str.length == 0) return "";
s = str.replace(/&/g, "&");
s = s.replace(/, "<");
s = s.replace(/>/g, ">");
s = s.replace(/ /g, " ");
s = s.replace(/\'/g, "'");
s = s.replace(/\"/g, """);
s = s.replace(/
/g, "
");
return s;
}
export const html_decode = (str) =>
{
var s = "";
if (str.length == 0) return "";
s = str.replace(/&/g, "&");
s = s.replace(/</g, ");
s = s.replace(/>/g, ">");
s = s.replace(/ /g, " ");
s = s.replace(/'/g, "\'");
s = s.replace(/"/g, "\"");
s = s.replace(/
/g, "
");
return s;
}
// ---- End ---
const REGX_HTML_ENCODE = /"|&|'||[\x00-\x20]|[\x7F-\xFF]|[\u0100-\u2700]/g;
const REGX_HTML_DECODE = /&\w+;|(\d+);/g;
const REGX_TRIM = /(^\s*)|(\s*$)/g;
const HTML_DECODE = {
": ",
">": ">",
"&": "&",
" ": " ",
'"': "\"",
"©": ""
// Add more
};
export const encodeHtml = (s) => {
s = (s != undefined) ? s : this.toString();
return (typeof s != "string") ? s :
s.replace(REGX_HTML_ENCODE,
function ($0) {
var c = $0.charCodeAt(0), r = [""];
c = (c == 0x20) ? 0xA0 : c;
r.push(c); r.push(";");
return r.join("");
});
};
export const decodeHtml = (s) => {
s = (s != undefined) ? s : this.toString();
return (typeof s != "string") ? s :
s.replace(REGX_HTML_DECODE,
function ($0, $1) {
var c = HTML_DECODE[$0];
if (c == undefined) {
// Maybe is Entity Number
if (!isNaN($1)) {
c = String.fromCharCode(($1 == 160) ? 32 : $1);
} else {
c = $0;
}
}
return c;
});
};
export const trim = (s) => {
s = (s != undefined) ? s : this.toString();
return (typeof s != "string") ? s :
s.replace(REGX_TRIM, "");
};
export const hashCode = () => {
var hash = this.__hash__, _char;
if (hash == undefined || hash == 0) {
hash = 0;
for (var i = 0, len = this.length; i < len; i++) {
_char = this.charCodeAt(i);
hash = 31 * hash + _char;
hash = hash & hash; // Convert to 32bit integer
}
hash = hash & 0x7fffffff;
}
this.__hash__ = hash;
return this.__hash__;
};