search.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. &:hover {
  49. background-color: #dfe4ed;
  50. }
  51. img {
  52. display: inline-block;
  53. height: 17px;
  54. margin-top: 10px;
  55. }
  56. }
  57. }
  58. .algolia-highlight {
  59. color: #409EFF;
  60. font-weight: bold;
  61. }
  62. .algolia-search-title {
  63. font-size: 14px;
  64. margin: 6px 0;
  65. line-height: 1.8;
  66. }
  67. .algolia-search-separator {
  68. padding: 0 6px;
  69. }
  70. .algolia-search-content {
  71. font-size: 12px;
  72. margin: 6px 0;
  73. line-height: 2.4;
  74. overflow: hidden;
  75. text-overflow: ellipsis;
  76. white-space: nowrap;
  77. }
  78. }
  79. </style>
  80. <script>
  81. import algoliasearch from 'algoliasearch';
  82. export default {
  83. data() {
  84. return {
  85. index: null,
  86. query: ''
  87. };
  88. },
  89. computed: {
  90. lang() {
  91. return this.$route.meta.lang;
  92. },
  93. placeholder() {
  94. return this.lang === 'zh-CN' ? '搜索文档' : 'Search';
  95. }
  96. },
  97. watch: {
  98. lang() {
  99. this.initIndex();
  100. }
  101. },
  102. methods: {
  103. initIndex() {
  104. const client = algoliasearch('9NLTR1QH8B', 'a75cbec97cda75ab7334fed9219ecc57');
  105. this.index = client.initIndex(`element-${ this.lang === 'zh-CN' ? 'zh' : 'en' }`);
  106. },
  107. querySearch(query, cb) {
  108. if (!query) return;
  109. this.index.search({ query, hitsPerPage: 6 }, (err, res) => {
  110. if (err) {
  111. console.error(err);
  112. return;
  113. }
  114. if (res.hits.length > 0) {
  115. cb(res.hits.map(hit => {
  116. let content = hit._highlightResult.content.value.replace(/\s+/g, ' ');
  117. const highlightStart = content.indexOf('<span class="algolia-highlight">');
  118. if (highlightStart > -1) {
  119. const startEllipsis = highlightStart - 15 > 0;
  120. content = (startEllipsis ? '...' : '') +
  121. content.slice(Math.max(0, highlightStart - 15), content.length);
  122. } else if (content.indexOf('|') > -1) {
  123. content = '';
  124. }
  125. return {
  126. anchor: hit.anchor,
  127. component: hit.component,
  128. highlightedCompo: hit._highlightResult.component.value,
  129. title: hit._highlightResult.title.value,
  130. content
  131. };
  132. }).concat({
  133. img: true
  134. }));
  135. } else {
  136. cb([]);
  137. }
  138. });
  139. },
  140. handleSelect(val) {
  141. if (val.img) return;
  142. const component = val.component || '';
  143. const anchor = val.anchor;
  144. this.$router.push(`/${ this.lang }/component/${ component }${ anchor ? `#${ anchor }` : '' }`);
  145. }
  146. },
  147. mounted() {
  148. this.initIndex();
  149. }
  150. };
  151. </script>