for each entry in the json. Here is the result: Các sản phẩmSản phẩm đơn được sử dụng để hiển thị thông tin về chỉ một sản phẩm. Nó trống và ẩn trên tải trang. Khi đạt được địa chỉ băm thích hợp, nó được điền với dữ liệu sản phẩm và hiển thị.
Trang lỗi chỉ bao gồm một thông báo lỗi để cho bạn biết khi nào bạn đã đạt được địa chỉ bị lỗi.
Mã JavaScript
Đầu tiên, hãy thực hiện bản xem trước nhanh chóng các chức năng và những gì họ làm.
script.js
$[function [] {
checkboxes.click[function [] {
// The checkboxes in our app serve the purpose of filters.
// Here on every click we add or remove filtering criteria from a filters object.
// Then we call this function which writes the filtering criteria in the url hash.
createQueryHash[filters];
}];
$.getJSON[ "products.json", function[ data ] {
// Get data about our products from products.json.
// Call a function that will turn that data into HTML.
generateAllProductsHTML[data];
// Manually trigger a hashchange to start the app.
$[window].trigger['hashchange'];
}];
$[window].on['hashchange', function[]{
// On every hash change the render function is called with the new hash.
// This is how the navigation of our app happens.
render[decodeURI[window.location.hash]];
}];
function render[url] {
// This function decides what type of page to show
// depending on the current url hash value.
}
function generateAllProductsHTML[data]{
// Uses Handlebars to create a list of products using the provided data.
// This function is called only once on page load.
}
function renderProductsPage[data]{
// Hides and shows products in the All Products Page depending on the data it recieves.
}
function renderSingleProductPage[index, data]{
// Shows the Single Product Page with appropriate data.
}
function renderFilterResults[filters, products]{
// Crates an object with filtered products and passes it to renderProductsPage.
renderProductsPage[results];
}
function renderErrorPage[]{
// Shows the error page.
}
function createQueryHash[filters]{
// Get the filters object, turn it into a string and write it into the hash.
}
}];
Hãy nhớ rằng khái niệm SPA là không có bất kỳ tải nào đang diễn ra trong khi ứng dụng đang chạy. Đó là lý do tại sao sau khi tải trang ban đầu, chúng tôi muốn ở trên cùng một trang, nơi mọi thứ chúng tôi cần đã được máy chủ tìm nạp.
Tuy nhiên, chúng tôi vẫn muốn có thể đi đâu đó trong ứng dụng và, ví dụ, sao chép URL và gửi nó cho một người bạn. Nếu chúng tôi không bao giờ thay đổi địa chỉ của ứng dụng, họ sẽ nhận được ứng dụng theo cách ban đầu, chứ không phải những gì bạn muốn chia sẻ với họ. Để giải quyết vấn đề này, chúng tôi viết thông tin về trạng thái của ứng dụng trong URL là #Hash. Băm không khiến trang tải lại và dễ dàng truy cập và thao tác.
Trên mỗi Hashchange, chúng tôi gọi là:
function render[url] {
// Get the keyword from the url.
var temp = url.split['/'][0];
// Hide whatever page is currently shown.
$['.main-content .page'].removeClass['visible'];
var map = {
// The Homepage.
'': function[] {
// Clear the filters object, uncheck all checkboxes, show all the products
filters = {};
checkboxes.prop['checked',false];
renderProductsPage[products];
},
// Single Products page.
'#product': function[] {
// Get the index of which product we want to show and call the appropriate function.
var index = url.split['#product/'][1].trim[];
renderSingleProductPage[index, products];
},
// Page with filtered products
'#filter': function[] {
// Grab the string after the '#filter/' keyword. Call the filtering function.
url = url.split['#filter/'][1].trim[];
// Try and parse the filters object from the query string.
try {
filters = JSON.parse[url];
}
// If it isn't a valid json, go back to homepage [ the rest of the code won't be executed ].
catch[err] {
window.location.hash = '#';
}
renderFilterResults[filters, products];
}
};
// Execute the needed function depending on the url keyword [stored in temp].
if[map[temp]]{
map[temp][];
}
// If the keyword isn't listed in the above - render the error page.
else {
renderErrorPage[];
}
}
Hàm này xem xét chuỗi bắt đầu của băm của chúng tôi, quyết định trang nào cần được hiển thị và gọi các chức năng theo.
Ví dụ: nếu băm là '#filter/{"lưu trữ": ["16"], "camera": ["5"]}', mã hóa của chúng tôi là '#filter'. Bây giờ chức năng kết xuất biết rằng chúng tôi muốn xem một trang có danh sách sản phẩm được lọc và sẽ điều hướng chúng tôi đến nó. Phần còn lại của băm sẽ được phân tích cú pháp vào một đối tượng và một trang với các sản phẩm được lọc sẽ được hiển thị, thay đổi trạng thái của ứng dụng.
Điều này chỉ được gọi là một lần khi khởi động và biến JSON của chúng tôi thành nội dung HTML5 thực tế thông qua tay lái.
function generateAllProductsHTML[data]{
var list = $['.all-products .products-list'];
var theTemplateScript = $["#products-template"].html[];
//Compile the template
var theTemplate = Handlebars.compile [theTemplateScript];
list.append [theTemplate[data]];
// Each products has a data-index attribute.
// On click change the url hash to open up a preview for this product only.
// Remember: every hashchange triggers the render function.
list.find['li'].on['click', function [e] {
e.preventDefault[];
var productIndex = $[this].data['index'];
window.location.hash = 'product/' + productIndex;
}]
}
Hàm này nhận được một đối tượng chỉ chứa những sản phẩm chúng tôi muốn hiển thị và hiển thị chúng.
function renderProductsPage[data]{
var page = $['.all-products'],
allProducts = $['.all-products .products-list > li'];
// Hide all the products in the products list.
allProducts.addClass['hidden'];
// Iterate over all of the products.
// If their ID is somewhere in the data object remove the hidden class to reveal them.
allProducts.each[function [] {
var that = $[this];
data.forEach[function [item] {
if[that.data['index'] == item.id]{
that.removeClass['hidden'];
}
}];
}];
// Show the page itself.
// [the render function hides all pages so we need to show the one we want].
page.addClass['visible'];
}
Hiển thị trang xem trước sản phẩm duy nhất:
function renderSingleProductPage[index, data]{
var page = $['.single-product'],
container = $['.preview-large'];
// Find the wanted product by iterating the data object and searching for the chosen index.
if[data.length]{
data.forEach[function [item] {
if[item.id == index]{
// Populate '.preview-large' with the chosen product's data.
container.find['h3'].text[item.name];
container.find['img'].attr['src', item.image.large];
container.find['p'].text[item.description];
}
}];
}
// Show the page.
page.addClass['visible'];
}
Lấy tất cả các sản phẩm, lọc chúng dựa trên truy vấn của chúng tôi và trả về một đối tượng với kết quả.
function renderFilterResults[filters, products]{
// This array contains all the possible filter criteria.
var criteria = ['manufacturer','storage','os','camera'],
results = [],
isFiltered = false;
// Uncheck all the checkboxes.
// We will be checking them again one by one.
checkboxes.prop['checked', false];
criteria.forEach[function [c] {
// Check if each of the possible filter criteria is actually in the filters object.
if[filters[c] && filters[c].length]{
// After we've filtered the products once, we want to keep filtering them.
// That's why we make the object we search in [products] to equal the one with the results.
// Then the results array is cleared, so it can be filled with the newly filtered data.
if[isFiltered]{
products = results;
results = [];
}
// In these nested 'for loops' we will iterate over the filters and the products
// and check if they contain the same values [the ones we are filtering by].
// Iterate over the entries inside filters.criteria [remember each criteria contains an array].
filters[c].forEach[function [filter] {
// Iterate over the products.
products.forEach[function [item]{
// If the product has the same specification value as the one in the filter
// push it inside the results array and mark the isFiltered flag true.
if[typeof item.specs[c] == 'number']{
if[item.specs[c] == filter]{
results.push[item];
isFiltered = true;
}
}
if[typeof item.specs[c] == 'string']{
if[item.specs[c].toLowerCase[].indexOf[filter] != -1]{
results.push[item];
isFiltered = true;
}
}
}];
// Here we can make the checkboxes representing the filters true,
// keeping the app up to date.
if[c && filter]{
$['input[name='+c+'][value='+filter+']'].prop['checked',true];
}
}];
}
}];
// Call the renderProductsPage.
// As it's argument give the object with filtered products.
renderProductsPage[results];
}
Hiển thị trạng thái lỗi:
function renderErrorPage[]{
var page = $['.error'];
page.addClass['visible'];
}
Chuỗi hóa đối tượng bộ lọc và ghi nó vào băm.
function createQueryHash[filters]{
// Here we check if filters isn't empty.
if[!$.isEmptyObject[filters]]{
// Stringify the object via JSON.stringify and write it after the '#filter' keyword.
window.location.hash = '#filter/' + JSON.stringify[filters];
}
else{
// If it's empty change the hash to '#' [the homepage].
window.location.hash = '#';
}
}
Sự kết luận
Các ứng dụng một trang là hoàn hảo khi bạn muốn mang lại cho dự án của mình một cảm giác năng động và trôi chảy hơn, và với sự giúp đỡ của một số lựa chọn thiết kế thông minh, bạn có thể cung cấp cho khách truy cập một trải nghiệm được đánh bóng, dễ chịu.
Bootstrap Studio
Công cụ thiết kế web mang tính cách mạng để tạo các trang web và ứng dụng đáp ứng.
Tìm hiểu thêm