使用搜尋小工具建立搜尋介面

搜尋小工具提供網頁應用程式的可自訂搜尋介面。 加入小工具只需少量的 HTML 和 JavaScript 實作並啟用常見的搜尋功能,例如 facet 和分頁。個人中心 也可以使用 CSS 和 JavaScript 自訂介面的部分。

如果您需要比小工具提供的更多彈性,可以考慮使用 Query API。如要進一步瞭解如何使用 Query API 建立搜尋介面, 請參閱使用 Query API 建立搜尋介面

建構搜尋介面

建構搜尋介面需要幾個步驟:

  1. 設定搜尋應用程式
  2. 產生應用程式的用戶端 ID
  3. 為搜尋框和結果新增 HTML 標記
  4. 在網頁上載入小工具
  5. 初始化小工具

設定搜尋應用程式

每個搜尋介面都必須在 管理控制台。搜尋應用程式會提供額外的 包括資料來源、商情項目 以及搜尋品質設定

如要建立搜尋應用程式,請參閱 建立自訂搜尋體驗

產生應用程式的用戶端 ID

除了 設定 Google Cloud Search API 的存取權, 您也必須產生網頁應用程式的用戶端 ID。

設定專案

設定專案時:

  • 選取「網路瀏覽器」用戶端類型
  • 提供來源 URI
  • 記下建立的用戶端 ID。您需要用戶端 ID 才能 或完成後續步驟用戶端密碼不需要

如需詳細資訊,請參閲 用戶端網頁應用程式適用的 OAuth 2.0

新增 HTML 標記

小工具需要少量 HTML 才能運作。個人中心 必須提供:

  • 搜尋框的 input 元素。
  • 將建議彈出式視窗固定到其中的元素。
  • 用於包含搜尋結果的元素。
  • (選用) 提供元素以包含 facet 控制項。

下列 HTML 程式碼片段顯示搜尋小工具的 HTML,其中 要繫結的元素以 id 屬性識別:

serving/widget/public/with_css/index.html
<div id="search_bar">
  <div id="suggestions_anchor">
    <input type="text" id="search_input" placeholder="Search for...">
  </div>
</div>
<div id="facet_results"></div>
<div id="search_results"></div>

載入小工具

系統會透過載入器指令碼動態載入小工具。包含 載入器,請使用 <script> 標記,如下所示:

serving/widget/public/with_css/index.html
<!-- Google API loader -->
<script src="https://apis.google.com/js/api.js?mods=enable_cloud_search_widget&onload=onLoad" async defer></script>

您必須在指令碼標記中提供 onload 回呼。這個函式稱為 並在載入器準備就緒時啟動載入器準備就緒後,繼續載入小工具 呼叫 gapi.load() 載入 API 用戶端、Google 登入和 Cloud Search 模組。

serving/widget/public/with_css/app.js
/**
* Load the cloud search widget & auth libraries. Runs after
* the initial gapi bootstrap library is ready.
*/
function onLoad() {
  gapi.load('client:auth2:cloudsearch-widget', initializeApp)
}

系統會在所有模組都呼叫完成後呼叫 initializeApp() 函式 就會引發這個事件。

初始化小工具

首先,請呼叫 將 gapi.client.init()gapi.auth2.init() 替換為產生的用戶端 ID 以及 https://www.googleapis.com/auth/cloud_search.query 範圍接下來,請使用 《gapi.cloudsearch.widget.resultscontainer.Builder》和 用於設定小工具的 gapi.cloudsearch.widget.searchbox.Builder 類別 並將其繫結至 HTML 元素

以下範例說明如何初始化小工具:

serving/widget/public/with_css/app.js
/**
 * Initialize the app after loading the Google API client &
 * Cloud Search widget.
 */
function initializeApp() {
  // Load client ID & search app.
  loadConfiguration().then(function() {
    // Set API version to v1.
    gapi.config.update('cloudsearch.config/apiVersion', 'v1');

    // Build the result container and bind to DOM elements.
    var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setSearchResultsContainerElement(document.getElementById('search_results'))
      .setFacetResultsContainerElement(document.getElementById('facet_results'))
      .build();

    // Build the search box and bind to DOM elements.
    var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setInput(document.getElementById('search_input'))
      .setAnchor(document.getElementById('suggestions_anchor'))
      .setResultsContainer(resultsContainer)
      .build();
  }).then(function() {
    // Init API/oauth client w/client ID.
    return gapi.auth2.init({
        'clientId': clientId,
        'scope': 'https://www.googleapis.com/auth/cloud_search.query'
    });
  });
}

上述範例參照了定義如下的兩個設定變數:

serving/widget/public/with_css/app.js
/**
* Client ID from OAuth credentials.
*/
var clientId = "...apps.googleusercontent.com";

/**
* Full resource name of the search application, such as
* "searchapplications/<your-id>".
*/
var searchApplicationName = "searchapplications/...";

自訂登入體驗

根據預設,小工具會提示使用者登入並授權應用程式 開始輸入查詢的同時別擔心!您可以使用 網站專用 Google 登入 為使用者提供更符合個人需求的登入體驗。

直接授權使用者

使用「使用 Google 帳戶登入」功能監控 使用者並視需求登入或登出帳戶例如,下列 範例:觀察 isSignedIn 以便監控登入變更 使用 GoogleAuth.signIn() 透過按鈕啟動登入的方法 點擊:

serving/widget/public/with_signin/app.js
// Handle sign-in/sign-out.
let auth = gapi.auth2.getAuthInstance();

// Watch for sign in status changes to update the UI appropriately.
let onSignInChanged = (isSignedIn) => {
  // Update UI to switch between signed in/out states
  // ...
}
auth.isSignedIn.listen(onSignInChanged);
onSignInChanged(auth.isSignedIn.get()); // Trigger with current status.

// Connect sign-in/sign-out buttons.
document.getElementById("sign-in").onclick = function(e) {
  auth.signIn();
};
document.getElementById("sign-out").onclick = function(e) {
  auth.signOut();
};

詳情請參閱「使用 Google 帳戶登入」一文。

自動登入使用者

您可以藉由預先授權 代表貴機構使用者的應用程式這種技術 在使用 Cloud Identity Aware Proxy 的情況下也相當實用 來保護應用程式

詳情請參閱在 IT 應用程式中使用 Google 登入功能

自訂介面

您可以透過組合變更搜尋介面的外觀 :

  • 使用 CSS 覆寫樣式
  • 使用轉接器裝飾元素
  • 使用轉接程式建立自訂元素

使用 CSS 覆寫樣式

搜尋小工具提供專屬的 CSS,方便設定建議和結果元素的樣式 以及分頁控制項您可以視需要重新調整這些元素的樣式。

載入期間,搜尋小工具會動態載入預設樣式表。 這會在應用程式樣式表載入後進行,提高優先順序 規則的意義為確保您自訂的樣式的優先順序高於預設樣式 使用祖系選取器來提高預設規則的明確性。

舉例來說,如果下列規則是在靜態資料中載入,則不會產生任何影響 文件中的 linkstyle 標記。

.cloudsearch_suggestion_container {
  font-size: 14px;
}

而是應該使用祖系容器的 ID 或類別限定規則。 。

#suggestions_anchor .cloudsearch_suggestion_container {
  font-size: 14px;
}

如需小工具產生的支援類別與範例 HTML 清單,請參閱 支援的 CSS 類別參考資料。

使用轉接器裝飾元素

如要在算繪前裝飾元素,請建立並重新放大 導入其中一種裝飾方法的轉接程式,例如 decorateSuggestionElement敬上 或 decorateSearchResultElement.

舉例來說,下列轉接器會在建議中加入自訂類別 。

serving/widget/public/with_decorated_element/app.js
/**
 * Search box adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.decorateSuggestionElement = function(element) {
  element.classList.add('my-suggestion');
}

/**
 * Results container adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.decorateSearchResultElement = function(element) {
  element.classList.add('my-result');
}

如要在初始化小工具時註冊轉接程式,請使用 setAdapter() 各個 Builder 類別中的方法:

serving/widget/public/with_decorated_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

裝飾器可以修改容器元素的屬性,也可以修改任何 子元素。子元素可能會在裝飾時加入或移除。 不過,如果要變更元素結構,請考慮建立 元素,而不是裝飾元素。

使用轉接程式建立自訂元素

如要為建議、商情項目容器或搜尋結果建立自訂元素, 建立及註冊 createSuggestionElementcreateFacetResultElement、 或 createSearchResultElement 以回應表示

下列轉接程式說明如何建立自訂建議和搜尋結果 使用 HTML <template> 標記的元素。

serving/widget/public/with_custom_element/app.js
/**
 * Search box adapter that overrides creation of suggestion elements.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.createSuggestionElement = function(suggestion) {
  let template = document.querySelector('#suggestion_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.suggested_query').textContent = suggestion.suggestedQuery;
  return fragment.firstElementChild;
}

/**
 * Results container adapter that overrides creation of result elements.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.createSearchResultElement = function(result) {
  let template = document.querySelector('#result_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.title').textContent = result.title;
  fragment.querySelector('.title').href = result.url;
  let snippetText = result.snippet != null ?
    result.snippet.snippet : '';
  fragment.querySelector('.query_snippet').innerHTML = snippetText;
  return fragment.firstElementChild;
}

如要在初始化小工具時註冊轉接程式,請使用 setAdapter() 各個 Builder 類別中的方法:

serving/widget/public/with_custom_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

使用 createFacetResultElement 建立自訂 facet 元素 須遵守以下幾項限制:

  • 您必須將 CSS 類別 cloudsearch_facet_bucket_clickable 附加至 元素:使用者點擊就能切換值區。
  • 您必須使用 CSS 將每個值區納入包含的元素中 cloudsearch_facet_bucket_container 類別。
  • 顯示值區的順序必須與其在 回應。

例如,下列程式碼片段會改用連結呈現 facet 勾選方塊。

serving/widget/public/with_custom_facet/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}

ResultsContainerAdapter.prototype.createFacetResultElement = function(result) {
  // container for the facet
  var container = document.createElement('div');

  // Add a label describing the facet (operator/property)
  var label = document.createElement('div')
  label.classList.add('facet_label');
  label.textContent = result.operatorName;
  container.appendChild(label);

  // Add each bucket
  for(var i in result.buckets) {
    var bucket = document.createElement('div');
    bucket.classList.add('cloudsearch_facet_bucket_container');

    // Extract & render value from structured value
    // Note: implementation of renderValue() not shown
    var bucketValue = this.renderValue(result.buckets[i].value)
    var link = document.createElement('a');
    link.classList.add('cloudsearch_facet_bucket_clickable');
    link.textContent = bucketValue;
    bucket.appendChild(link);
    container.appendChild(bucket);
  }
  return container;
}

// Renders a value for user display
ResultsContainerAdapter.prototype.renderValue = function(value) {
  // ...
}

自訂搜尋行為

「搜尋應用程式」設定代表預設值 都是靜態的。 篩選器或商情項目 (例如允許使用者切換資料來源) 攔截搜尋要求以覆寫搜尋應用程式設定 搭配轉接頭。

使用 interceptSearchRequest敬上 方法來修改對 搜尋 API 執行的程式碼

舉例來說,下列轉接器會攔截限制查詢的要求 使用者選取的來源:

serving/widget/public/with_request_interceptor/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}
ResultsContainerAdapter.prototype.interceptSearchRequest = function(request) {
  if (!this.selectedSource || this.selectedSource == 'ALL') {
    // Everything selected, fall back to sources defined in the search
    // application.
    request.dataSourceRestrictions = null;
  } else {
    // Restrict to a single selected source.
    request.dataSourceRestrictions = [
      {
        source: {
          predefinedSource: this.selectedSource
        }
      }
    ];
  }
  return request;
}

如要在初始化小工具時註冊轉接程式,請使用 setAdapter()敬上 ResultsContainer

serving/widget/public/with_request_interceptor/app.js
var resultsContainerAdapter = new ResultsContainerAdapter();
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(resultsContainerAdapter)
  // ...
  .build();

下列 HTML 可用於顯示篩選依據的選取框 資料來源:

serving/widget/public/with_request_interceptor/index.html
<div>
  <span>Source</span>
  <select id="sources">
    <option value="ALL">All</option>
    <option value="GOOGLE_GMAIL">Gmail</option>
    <option value="GOOGLE_DRIVE">Drive</option>
    <option value="GOOGLE_SITES">Sites</option>
    <option value="GOOGLE_GROUPS">Groups</option>
    <option value="GOOGLE_CALENDAR">Calendar</option>
    <option value="GOOGLE_KEEP">Keep</option>
  </select>
</div>

下列程式碼會監聽變更、設定選擇及 會視需要重新執行查詢。

serving/widget/public/with_request_interceptor/app.js
// Handle source selection
document.getElementById('sources').onchange = (e) => {
  resultsContainerAdapter.selectedSource = e.target.value;
  let request = resultsContainer.getCurrentRequest();
  if (request.query) {
    // Re-execute if there's a valid query. The source selection
    // will be applied in the interceptor.
    resultsContainer.resetState();
    resultsContainer.executeRequest(request);
  }
}

您也可以使用 interceptSearchResponse敬上 。

固定 API 版本

根據預設,小工具會使用最新的 API 穩定版本。如要鎖定 指定版本,則請將 cloudsearch.config/apiVersion 設定參數 先套用偏好版本,再初始化小工具。

serving/widget/public/basic/app.js
gapi.config.update('cloudsearch.config/apiVersion', 'v1');

如果未設定或設為無效值,API 版本將預設為 1.0。

固定小工具版本

為避免搜尋介面發生非預期的變更,請將 cloudsearch.config/clientVersion 設定參數,如下所示:

gapi.config.update('cloudsearch.config/clientVersion', 1.1);

如果未設定或設為無效值,小工具版本會預設為 1.0。

保護搜尋介面

搜尋結果包含高度機密資訊。奉行最佳做法 強化網頁應用程式安全性,尤其是針對 點擊劫持攻擊。

詳情請參閱 OWASP Guide Project

啟用偵錯功能

使用 interceptSearchRequest 即可開啟搜尋小工具的偵錯功能。例如:

  if (!request.requestOptions) {
  // Make sure requestOptions is populated
  request.requestOptions = {};
  }
  // Enable debugging
  request.requestOptions.debugOptions = {enableDebugging: true}

  return request;