过滤是各种网页上常用的功能。它允许用户使用提供的参数缩小数据(如类别、标签、其他特征)的范围。让我们创造我们自己的!
页面过滤的一个常见示例是允许用户根据尺寸、颜色、品牌等过滤产品的电子商务网站。
在本教程中,我们将重新创建 作者页面并实现一个过滤器组件,以允许我们根据文章的类别过滤文章。
数据过滤器演示
让我们来看看我们将构建什么——单击演示中的过滤器标签以切换显示的教程:
See the Pen How to filter a list with a single param in JavaScript by Envato Tuts+ (@tutsplus) on CodePen.
1.布局和样式
对于此演示,我们将克隆作者页面,以便直接从实时站点获取标记和样式。我们将关注的主要组件是过滤器和显示的帖子,因此我们将创建一个<div class="filter-container">和<div class="posts-container">并在 javascript 中定位它们。
我们将在 css 中设置这些容器及其内容的样式:
.posts-container { display: flex; flex-wrap: wrap; } .post { position: relative; width: 300px; margin-right: 30px; margin-bottom: 40px; border: 1px solid #e1e8ed; border-radius: 4px; margin-top: 13px; min-height: 300px; height: auto; } .filter-container { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 10px; padding: 32px 0; border-top: 1px solid #e4e4e4; border-bottom: 1px solid #e4e4e4; margin-bottom: 32px; } .filter-button { transition: background-color 200ms, color 200ms; background-color: transparent; font: inherit; cursor: pointer; display: inline-block; padding: 0 8px; color: #717171; border: 1px solid #9b9b9b; border-radius: 25px; font-size: 14px; white-space: nowrap; } .filter-button:hover { background-color: #f3f3f3; color: #3a3a3a; } .filter-button.is-active { background-color: #0085b6; border-color: #0085b6; color: #fff; }
2.使用fetch api获取页面数据
在此演示中,我们将使用Fetch API检索从作者页面抓取并存储在Github gist中的模拟数据。
查看本教程,了解如何使用 JavaScript 从网页中抓取数据。
我们的模拟数据具有以下格式:
[ { "title": "", "link": "", "image": "", "categories": [ ] }, ... ]
这是从脚本中获取数据的脚本:
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" ).then(async (response) => { // handle response data });
一旦我们获得了获取的数据,我们就可以操作数据并将其附加到页面上。
3.向网页追加数据
对于我们获取的响应中的每个对象,我们将创建一个将在页面上显示数据的帖子 div。首先,让我们定义我们的全局变量:
let postsData = ""; const postsContainer = document.queryselector(".posts-container");
然后我们将创建一个函数createPost()来处理将新的 div 附加到 posts-container 元素。在此函数中,我们创建了一个新的 div 元素,其类名post并将其 innerhtml 设置为我们要显示的数据。
const createPost = (postData) => { const { title, link, image, categories } = postData; const post = document.createElement("div"); post.className = "post"; post.innerHTML = ` <a class="post-preview" href="${link}" target="_blank"> <img class="post-image" src="${image}"> </a> <div class="post-content"> <p class="post-title">${title}</p> <div class="post-tags"> ${categories .map((category) => { return '<span class="post-tag">' + category + "</span>"; }) .join("")} </div> </div> `; postsContainer.append(post); };
在我们的帖子 innerHTML 中,我们使用我们的join("")方法categories.map()删除每个数组中包含的“,”符号。
现在我们可以更新响应函数以createPost()在获取数据后调用该函数:
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" ).then(async (response) => { postsData = await response.json(); postsData.map((post) => createPost(post)); });
4.从响应中获取过滤器参数
由于我们使用的是 javaScript,因此我们可以映射我们的响应以创建过滤器参数的动态列表。让我们为过滤器数据包含全局变量:
let filterData = ""; const filterContainer = document.querySelector(".filter-container");
现在我们要编写一个脚本,对每个响应对象中的类别数组进行排序并返回一个唯一列表。我们可以更新我们的响应对象来处理获取过滤器参数的唯一列表
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" ).then(async (response) => { postsData = await response.json(); postsData.map((post) => createPost(post)); filterData = [ ...new Set( postsData .map((post) => post.categories) .reduce((acc, curVal) => acc.concat(curVal), []) ) ]; });
分解我们的 filterData 的代码:
我们[... new Set]用来创建一个唯一值数组。Set返回一个具有唯一值的对象,扩展语法 [...] 将该对象转换为一个数组。
我们通过 postsData 进行映射,以获取数据响应中每个帖子对象的类别数组。
我们使用该.reduce()方法将每个帖子对象的类别数组组合成一个数组。
一旦我们从帖子类别中获得了我们的唯一过滤器值数组,我们就可以创建一个函数来将每个过滤器附加到页面。我们将创建一个新的按钮元素并设置 innerText 和 className。我们还将设置一个“数据状态”属性来处理单击时更改按钮状态。
每个过滤器按钮都会有一个点击事件监听器设置为 handleButtonClick 函数,它将负责处理过滤逻辑。
const createFilter = (filter) => { const filterButton = document.createElement("button"); filterButton.className = "filter-button"; filterButton.innerText = filter; filterButton.setAttribute('data-state', 'inactive'); filterButton.addeventListener("click", (e) => handleButtonClick(e, filter) ); filterContainer.append(filterButton); };
并更新我们的响应函数以调用该createFilter()函数:
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" ).then(async (response) => { postsData = await response.json(); postsData.map((post) => createPost(post)); filterData = [ ...new Set( postsData .map((post) => post.categories) .reduce((acc, curVal) => acc.concat(curVal), []) ) ]; filterData.map((filter) => createFilter(filter)); });
5.点击时处理过滤
现在我们已经获得了过滤按钮和初始数据,我们可以定义一个函数来处理单击按钮时过滤数据。这可以使用.filter()posts 数据数组上的方法来完成。
这是我们将用于过滤数据的逻辑:
创建一个handleFilterPosts()接受过滤参数的函数
使用该.filter()方法根据过滤器参数过滤我们的帖子数据
清除 posts-container 中的所有元素并将新的 filteredData 附加到容器中。
const handleFilterPosts = (param) => { let filteredPosts = [...postsData].filter(post => post.categories.includes(param)) postsContainer.innerHTML = ""; filteredPosts.map(post => createPost(post)) };
我们想要检测按钮何时被点击并更新按钮状态。在本教程中,我们将切换按钮,如果单击一次,按钮将设置为活动状态,如果再次单击,按钮将设置为非活动状态。
const handleButtonClick = (e, param) => { const button = e.target; const buttonState = button.getAttribute('data-state'); if (buttonState =='inactive') { button.classList.add('is-active'); button.setAttribute('data-state', 'active'); } else { button.classList.remove('is-active'); button.setAttribute('data-state', 'inactive') } }
我们还想确保一次只选择一个按钮,如果没有选择任何按钮,帖子应显示默认数据,以便我们可以创建函数来处理该逻辑:
const resetFilterButtons = (currentButton) => { const filterButtons = document.querySelectorAll('.filter-button'); [...filterButtons].map(button => { if (button != currentButton) { button.classList.remove('is-active'); button.setAttribute('data-state', 'inactive') } }) } const resetPosts = () => { postsContainer.innerHTML = ""; postsData.map((post) => createPost(post)); }
最后,我们可以更新我们的按钮点击功能:
const handleButtonClick = (e, param) => { const button = e.target; const buttonState = button.getAttribute('data-state'); resetFilterButtons(button); if (buttonState =='inactive') { button.classList.add('is-active'); button.setAttribute('data-state', 'active'); handleFilterPosts(param) } else { button.classList.remove('is-active'); button.setAttribute('data-state', 'inactive') resetPosts() } }
结论
至此,我们已经使用原生 JavaScript 为网页上的数据完全构建了一个过滤组件!
See the Pen How to filter a list with a single param in JavaScript by Envato Tuts+ (@tutsplus) on CodePen.
发表评论