Vue集成 #

安装 #

bash
npm install algoliasearch vue-instantsearch

基本配置 #

Vue 3 配置 #

javascript
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import InstantSearch from 'vue-instantsearch/vue3/es';

const app = createApp(App);
app.use(InstantSearch);
app.mount('#app');

创建搜索组件 #

vue
<template>
  <ais-instant-search
    index-name="products"
    :search-client="searchClient"
  >
    <ais-search-box placeholder="搜索商品..." />
    <ais-hits>
      <template v-slot:item="{ item }">
        <div class="hit">
          <h3>{{ item.name }}</h3>
          <p>${{ item.price }}</p>
        </div>
      </template>
    </ais-hits>
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch';

export default {
  data() {
    return {
      searchClient: algoliasearch('APP_ID', 'SEARCH_KEY')
    };
  }
};
</script>

核心组件 #

vue
<ais-instant-search
  index-name="products"
  :search-client="searchClient"
  :initial-ui-state="{
    products: {
      query: 'iphone',
      page: 1
    }
  }"
>
  <!-- 子组件 -->
</ais-instant-search>
vue
<ais-search-box
  placeholder="搜索商品..."
  :autofocus="true"
  :search-as-you-type="true"
  :show-reset="true"
  :show-submit="true"
  :show-loading-indicator="true"
/>

ais-hits #

vue
<ais-hits>
  <template v-slot:item="{ item }">
    <div class="hit">
      <img :src="item.image" :alt="item.name" />
      <h3>{{ item.name }}</h3>
      <p>${{ item.price }}</p>
    </div>
  </template>
</ais-hits>

分页组件 #

ais-pagination #

vue
<ais-pagination
  :show-first="true"
  :show-previous="true"
  :show-next="true"
  :show-last="true"
  :padding="2"
/>

ais-infinite-hits #

vue
<ais-infinite-hits>
  <template v-slot:item="{ item }">
    <div class="hit">
      <h3>{{ item.name }}</h3>
      <p>${{ item.price }}</p>
    </div>
  </template>
  
  <template v-slot:loadMore="{ refineNext, isLastPage }">
    <button
      :disabled="isLastPage"
      @click="refineNext"
    >
      加载更多
    </button>
  </template>
</ais-infinite-hits>

过滤组件 #

ais-refinement-list #

vue
<ais-refinement-list
  attribute="brand"
  searchable
  searchable-placeholder="搜索品牌"
  :show-more="true"
  :show-more-limit="20"
  :limit="5"
/>

ais-menu #

vue
<ais-menu
  attribute="category"
  :show-more="true"
  :limit="5"
/>

ais-toggle-refinement #

vue
<ais-toggle-refinement
  attribute="inStock"
  label="仅显示有货"
/>

ais-range-input #

vue
<ais-range-input
  attribute="price"
  :min="0"
  :max="2000"
  :precision="0"
/>

排序组件 #

ais-sort-by #

vue
<ais-sort-by
  :items="[
    { value: 'products', label: '相关度' },
    { value: 'products_price_asc', label: '价格升序' },
    { value: 'products_price_desc', label: '价格降序' }
  ]"
/>

状态组件 #

ais-current-refinements #

vue
<ais-current-refinements>
  <template v-slot:item="{ item }">
    <span>{{ item.label }}: {{ item.display }}</span>
  </template>
</ais-current-refinements>

ais-clear-refinements #

vue
<ais-clear-refinements
  :excluded-attributes="['query']"
/>

ais-stats #

vue
<ais-stats>
  <template v-slot="{ nbHits, processingTimeMS }">
    找到 {{ nbHits }} 个结果,耗时 {{ processingTimeMS }}ms
  </template>
</ais-stats>

自定义组件 #

使用Composition API #

vue
<template>
  <ais-instant-search
    index-name="products"
    :search-client="searchClient"
  >
    <CustomSearchBox />
    <CustomHits />
  </ais-instant-search>
</template>

<script setup>
import { useSearchBox, useHits } from 'vue-instantsearch/vue3/es';

const searchClient = algoliasearch('APP_ID', 'SEARCH_KEY');

function CustomSearchBox() {
  const { query, refine } = useSearchBox();
  
  return {
    query,
    refine
  };
}

function CustomHits() {
  const { hits } = useHits();
  
  return {
    hits
  };
}
</script>

使用Options API #

vue
<template>
  <div>
    <input
      :value="query"
      @input="refine($event.target.value)"
      placeholder="搜索..."
    />
    <div v-for="hit in hits" :key="hit.objectID">
      <h3>{{ hit.name }}</h3>
      <p>${{ hit.price }}</p>
    </div>
  </div>
</template>

<script>
import { connectSearchBox, connectHits } from 'instantsearch.js/es/connectors';

export default {
  props: ['query', 'refine', 'hits']
};

export const CustomSearchBox = connectSearchBox({
  render({ currentRefinement, refine }) {
    return {
      query: currentRefinement,
      refine
    };
  }
});
</script>

完整示例 #

vue
<template>
  <ais-instant-search
    index-name="products"
    :search-client="searchClient"
  >
    <ais-configure
      :hits-per-page.camel="12"
      :attributes-to-highlight.camel="['name', 'description']"
    />
    
    <div class="search-container">
      <aside class="filters">
        <h3>筛选</h3>
        <ais-clear-refinements />
        
        <h4>品牌</h4>
        <ais-refinement-list attribute="brand" searchable />
        
        <h4>分类</h4>
        <ais-refinement-list attribute="category" />
        
        <h4>价格</h4>
        <ais-refinement-list attribute="price_range" />
      </aside>
      
      <main class="results">
        <div class="search-header">
          <ais-search-box placeholder="搜索商品..." />
          <ais-sort-by
            :items="[
              { value: 'products', label: '相关度' },
              { value: 'products_price_asc', label: '价格升序' },
              { value: 'products_price_desc', label: '价格降序' }
            ]"
          />
        </div>
        
        <div class="search-info">
          <ais-stats>
            <template v-slot="{ nbHits }">
              找到 {{ nbHits }} 个结果
            </template>
          </ais-stats>
          <ais-current-refinements />
        </div>
        
        <ais-hits>
          <template v-slot:item="{ item }">
            <article class="product-card">
              <img :src="item.image" :alt="item.name" />
              <div class="product-info">
                <h3>{{ item.name }}</h3>
                <p class="brand">{{ item.brand }}</p>
                <p class="price">${{ item.price }}</p>
                <p class="rating">★ {{ item.rating }}</p>
              </div>
            </article>
          </template>
        </ais-hits>
        
        <ais-pagination />
      </main>
    </div>
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch';
import 'instantsearch.css/themes/algolia.css';

export default {
  data() {
    return {
      searchClient: algoliasearch('APP_ID', 'SEARCH_KEY')
    };
  }
};
</script>

<style scoped>
.search-container {
  display: flex;
  gap: 20px;
}

.filters {
  width: 250px;
}

.results {
  flex: 1;
}

.product-card {
  border: 1px solid #eee;
  border-radius: 8px;
  padding: 16px;
}

.product-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}
</style>

样式定制 #

自定义类名 #

vue
<ais-search-box
  :class-names="{
    'ais-SearchBox': 'my-search-box',
    'ais-SearchBox-input': 'my-search-input',
    'ais-SearchBox-submit': 'my-search-submit'
  }"
/>

自定义样式 #

css
.my-search-box {
  margin-bottom: 20px;
}

.my-search-input {
  width: 100%;
  padding: 12px;
  border: 2px solid #ddd;
  border-radius: 8px;
}

.my-search-input:focus {
  border-color: #5468ff;
  outline: none;
}

总结 #

Vue集成要点:

要点 说明
核心组件 ais-instant-search, ais-search-box, ais-hits
过滤组件 ais-refinement-list, ais-menu, ais-toggle-refinement
分页组件 ais-pagination, ais-infinite-hits
插槽 v-slot:item, v-slot:loadMore
样式 class-names属性,自定义CSS

接下来,让我们学习 Node.js后端

最后更新:2026-03-28