search.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <template>
  2. <el-autocomplete
  3. v-model="query"
  4. size="small"
  5. popper-class="algolia-search"
  6. :fetch-suggestions="querySearch"
  7. :placeholder="placeholder"
  8. :trigger-on-focus="false"
  9. @select="handleSelect">
  10. <template scope="props">
  11. <p class="algolia-search-title" v-if="props.item.title">
  12. <span v-html="props.item.highlightedCompo"></span>
  13. <span class="algolia-search-separator">></span>
  14. <span v-html="props.item.title"></span>
  15. </p>
  16. <p
  17. class="algolia-search-content"
  18. v-if="props.item.content"
  19. v-html="props.item.content"></p>
  20. <img
  21. class="algolia-search-logo"
  22. src="../assets/images/search-by-algolia.svg"
  23. alt="algolia-logo"
  24. v-if="props.item.img">
  25. </template>
  26. </el-autocomplete>
  27. </template>
  28. <style>
  29. .algolia-search {
  30. width: 450px !important;
  31. .el-autocomplete-suggestion__list {
  32. position: static !important;
  33. padding-bottom: 31px;
  34. }
  35. li {
  36. border-bottom: solid 1px #ebebeb;
  37. &:last-child {
  38. border-bottom: none;
  39. position: absolute;
  40. bottom: 0;
  41. left: 0;
  42. width: 100%;
  43. background-color: #dfe4ed;
  44. border-bottom-left-radius: 4px;
  45. border-bottom-right-radius: 4px;
  46. box-sizing: border-box;
  47. text-align: right;
  48. img {
  49. display: inline-block;
  50. height: 17px;
  51. margin-top: 10px;
  52. }
  53. }
  54. }
  55. .algolia-highlight {
  56. color: #409EFF;
  57. font-weight: bold;
  58. }
  59. .algolia-search-title {
  60. font-size: 14px;
  61. margin: 6px 0;
  62. line-height: 1.8;
  63. }
  64. .algolia-search-separator {
  65. padding: 0 6px;
  66. }
  67. .algolia-search-content {
  68. font-size: 12px;
  69. margin: 6px 0;
  70. line-height: 2.4;
  71. }
  72. }
  73. </style>
  74. <script>
  75. import algoliasearch from 'algoliasearch';
  76. export default {
  77. data() {
  78. return {
  79. index: null,
  80. query: ''
  81. };
  82. },
  83. computed: {
  84. lang() {
  85. return this.$route.meta.lang;
  86. },
  87. placeholder() {
  88. return this.lang === 'zh-CN' ? '搜索文档' : 'Search';
  89. }
  90. },
  91. watch: {
  92. lang() {
  93. this.initIndex();
  94. }
  95. },
  96. methods: {
  97. initIndex() {
  98. const client = algoliasearch('9NLTR1QH8B', 'a75cbec97cda75ab7334fed9219ecc57');
  99. this.index = client.initIndex(`element-${ this.lang === 'zh-CN' ? 'zh' : 'en' }`);
  100. },
  101. querySearch(query, cb) {
  102. if (!query) return;
  103. this.index.search({ query, hitsPerPage: 6 }, (err, res) => {
  104. if (err) {
  105. console.error(err);
  106. return;
  107. }
  108. if (res.hits.length > 0) {
  109. cb(res.hits.map(hit => {
  110. let content = hit._highlightResult.content.value.replace(/\s+/g, ' ');
  111. const highlightStart = content.indexOf('<span class="algolia-highlight">');
  112. if (highlightStart > -1) {
  113. const highlightEnd = content.lastIndexOf('</span>');
  114. const startEllipsis = highlightStart - 15 > 0;
  115. const endEllipsis = highlightEnd + 22 < content.length;
  116. content = (startEllipsis ? '...' : '') +
  117. content.slice(Math.max(0, highlightStart - 15), Math.min(highlightEnd + 22, content.length)) +
  118. (endEllipsis ? '...' : '');
  119. } else if (content.indexOf('|') > -1) {
  120. content = '';
  121. }
  122. return {
  123. anchor: hit.anchor,
  124. component: hit.component,
  125. highlightedCompo: hit._highlightResult.component.value,
  126. title: hit._highlightResult.title.value,
  127. content
  128. };
  129. }).concat({
  130. img: true
  131. }));
  132. } else {
  133. cb([]);
  134. }
  135. });
  136. },
  137. handleSelect(val) {
  138. if (val.img) return;
  139. const component = val.component || '';
  140. const anchor = val.anchor;
  141. this.$router.push(`/${ this.lang }/component/${ component }${ anchor ? `#${ anchor }` : '' }`);
  142. }
  143. },
  144. mounted() {
  145. this.initIndex();
  146. }
  147. };
  148. </script>