本程式碼研究室將說明如何打造 Instagram 限時動態等內容 在網路上。建構元件時,我們會從 HTML、CSS 開始 那麼 JavaScript
查看我的網誌文章:打造短片故事元件 ,瞭解建構此元件時的漸進式強化功能。
設定
- 按一下「Remix to Edit」即可編輯專案。
- 開啟
app/index.html
。
HTML
我一直努力使用語意 HTML。
由於每個好友的故事數量不多,因此我覺得使用
每位好友的 <section>
元素和每則故事的 <article>
元素。
讓我們從頭開始吧。首先,我們需要建立容器
故事元件
在 <body>
中新增 <div>
元素:
<div class="stories">
</div>
新增一些 <section>
元素來代表好友:
<div class="stories">
<section class="user"></section>
<section class="user"></section>
<section class="user"></section>
<section class="user"></section>
</div>
新增一些 <article>
元素來代表故事:
<div class="stories">
<section class="user">
<article class="story" style="--bg: url(https://picsum.photos/480/840);"></article>
<article class="story" style="--bg: url(https://picsum.photos/480/841);"></article>
</section>
<section class="user">
<article class="story" style="--bg: url(https://picsum.photos/481/840);"></article>
</section>
<section class="user">
<article class="story" style="--bg: url(https://picsum.photos/481/841);"></article>
</section>
<section class="user">
<article class="story" style="--bg: url(https://picsum.photos/482/840);"></article>
<article class="story" style="--bg: url(https://picsum.photos/482/843);"></article>
<article class="story" style="--bg: url(https://picsum.photos/482/844);"></article>
</section>
</div>
- 我們目前使用圖片服務 (
picsum.com
) 來為故事設計原型。 - 每個
<article>
上的style
屬性都是載入預留位置的一部分 您將在下一節進一步瞭解這個主題
CSS
我們的內容隨時都展現風格。讓我們將這些骨頭轉換為客戶 或想與其互動從今天開始,我們決定以行動裝置為優先。
.stories
對於 <div class="stories">
容器,我們需要水平捲動容器。
做法如下:
- 將容器設為格線
- 設定每個子項來填入列軌
- 讓每個子項的寬度調整為行動裝置可視區域的寬度
格線將繼續將新的 100vw
寬欄放置在上一個儲存格的右側
一,直到標記所有的 HTML 元素都放下為止
![Chrome 和開發人員工具開啟,並以格狀檢視畫面顯示完整寬度版面配置](https://web.developers.google.cn/static/articles/codelab-building-a-stories-component/image/chrome-devtools-open-a-72aaa3c91f873.png?authuser=9&hl=zh-tw)
將下列 CSS 新增至 app/css/index.css
的底部:
.stories {
display: grid;
grid: 1fr / auto-flow 100%;
gap: 1ch;
}
現在我們有內容超出可視區域外,接下來要告訴大家
以及如何處理容器在 .stories
規則集中加入醒目顯示的程式碼行:
.stories {
display: grid;
grid: 1fr / auto-flow 100%;
gap: 1ch;
overflow-x: auto;
scroll-snap-type: x mandatory;
overscroll-behavior: contain;
touch-action: pan-x;
}
我們希望水平捲動,因此將 overflow-x
設為
auto
。當使用者捲動畫面時,我們希望元件能夠平穩地停留在下一個故事中
我們使用 scroll-snap-type: x mandatory
瞭解詳情
CSS 捲動 Snap 點中的 CSS
和過度捲動行為
閱讀完整版影片
父項容器和子項都必須同意捲動貼齊
就開始處理將以下程式碼新增至 app/css/index.css
的底部:
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
}
您的應用程式還不支援,但下方影片會說明
「scroll-snap-type
」已啟用並停用。啟用後,系統會為每個水平元素
捲動至下一篇故事如果停用,瀏覽器會使用
預設的捲動行為
這樣您就能捲動瀏覽好友頁面,但問題仍未解決 和我們一起解決的故事
.user
我們來在 .user
區段中建立疊加這些子項故事的版面配置。
編輯元素我們將透過實用的堆疊技巧來解決這個問題。
基本上我們要建立 1x1 方格,讓列和欄具有相同格線
建立 [story]
的別名,而每個故事格線項目將嘗試取得該空間,
形成堆疊
將醒目顯示的程式碼新增至 .user
規則集:
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
display: grid;
grid: [story] 1fr / [story] 1fr;
}
將下列規則集新增至 app/css/index.css
的底部:
.story {
grid-area: story;
}
現在,沒有絕對定位、浮點值或其他版面配置指令 新增元素後 我們仍在進入下一階段而且就像任何程式碼一樣 真厲害!實際做法則包含影片和網誌文章中的詳細說明。
.story
現在我們只需要設定故事項目的樣式。
我們先前提過,每個 <article>
元素的 style
屬性都是
預留位置載入技術:
<article class="story" style="--bg: url(https://picsum.photos/480/840);"></article>
我們將使用 CSS 的 background-image
屬性,以便為
一或多張背景圖片。我們可以依序排列這些元件
圖示,會在圖片載入完畢後自動顯示。目的地:
啟用後,我們會將圖片網址放入自訂屬性 (--bg
),並使用該屬性
加入載入預留位置
首先,請更新 .story
規則集,將漸層取代為背景圖片
等容器載入完成後將醒目顯示的程式碼新增至 .story
規則集:
.story {
grid-area: story;
background-size: cover;
background-image:
var(--bg),
linear-gradient(to top, lch(98 0 0), lch(90 0 0));
}
將 background-size
設為 cover
,可確保
因為系統會填滿該圖片定義 2 張背景圖片
我們可以提取名為 loading tombstone 的可靠 CSS 網路技巧:
- 背景圖片 1 (
var(--bg)
) 是我們內嵌在 HTML 中的網址 - 背景圖片 2 (
linear-gradient(to top, lch(98 0 0), lch(90 0 0))
為漸層色 載入網址時顯示
圖片下載完畢後,CSS 會自動以圖片取代漸層。
接下來,我們要新增一些 CSS 來移除部分行為,藉此加快瀏覽器執行速度。
將醒目顯示的程式碼新增至 .story
規則集:
.story {
grid-area: story;
background-size: cover;
background-image:
var(--bg),
linear-gradient(to top, lch(98 0 0), lch(90 0 0));
user-select: none;
touch-action: manipulation;
}
user-select: none
可避免使用者不小心選取文字touch-action: manipulation
會指示瀏覽器在這些互動 應視為觸控事件,這樣瀏覽器就會 決定是否要點擊網址
最後,加入一個 CSS 動畫,為故事之間的轉場加上動畫效果。將
已醒目顯示的程式碼加到 .story
規則集:
.story {
grid-area: story;
background-size: cover;
background-image:
var(--bg),
linear-gradient(to top, lch(98 0 0), lch(90 0 0));
user-select: none;
touch-action: manipulation;
transition: opacity .3s cubic-bezier(0.4, 0.0, 1, 1);
&.seen {
opacity: 0;
pointer-events: none;
}
}
.seen
類別會新增至需要退出的故事。
我取得了自訂的加/減速函式 (cubic-bezier(0.4, 0.0, 1,1)
)
Material Design 的加/減速設定
指南圖示 (捲動至「加速加/減速」部分)。
無論你喜歡什麼,也許會注意到pointer-events: none
而且你現在也抓到自己頭部我認為這是
解決方案的缺點我們需要這樣做,因為 .seen.story
元素
即使不可見,也能夠輕觸。透過設定
pointer-events
飛往none
,我們將玻璃故事打造成一個窗戶,然後偷偷告訴您
增加的使用者互動次數權衡利弊得失,而且不易管理
CSS 供應商我們不會在z-index
的東西上表演。我感覺好心情
保持。
JavaScript
短片故事元件的互動方式非常簡單:輕觸 按左方可返回,向左滑動可返回上一個畫面。使用者通常覺得很簡單 成為開發人員但我們會處理好多事。
設定
首先,請盡可能運算及儲存各種資訊。
在 app/js/index.js
加入以下程式碼:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
第一行 JavaScript 會擷取並儲存我們主要 HTML 的參照 元素根層級下一行會計算元素中間的位置,因此我們 可以決定輕觸是要前往快轉或倒轉。
州
接下來,我們要製作一個小型物件,並加入某些與邏輯相關的狀態。在本
我們只關注目前的報導在 HTML 標記中
擷取第一名好友和他們最近的故事新增醒目顯示的程式碼
至您的 app/js/index.js
:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
const state = {
current_story: stories.firstElementChild.lastElementChild
}
事件監聽器
現在,我們擁有足夠的邏輯,可以開始監聽使用者事件並引導事件。
老鼠
首先,監聽故事容器中的 'click'
事件。
將醒目顯示的程式碼新增至 app/js/index.js
:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
const state = {
current_story: stories.firstElementChild.lastElementChild
}
stories.addEventListener('click', e => {
if (e.target.nodeName !== 'ARTICLE')
return
navigateStories(
e.clientX > median
? 'next'
: 'prev')
})
如果點擊發生,但裝置沒有出現在 <article>
元素上,我們會負責操作,而不會執行任何動作。
如果是文章,我們會擷取滑鼠或手指的水平位置,
clientX
。我們尚未實作 navigateStories
,但引數
代表我們要前進的方向若使用者位置為
大於中位數,我們知道必須前往 next
,否則
prev
(上一個)。
鍵盤
現在我們來聽聽鍵盤的按下動作。如果按下「向下鍵」,
至 next
。如果是「向上箭頭」,請改為前往 prev
。
將醒目顯示的程式碼新增至 app/js/index.js
:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
const state = {
current_story: stories.firstElementChild.lastElementChild
}
stories.addEventListener('click', e => {
if (e.target.nodeName !== 'ARTICLE')
return
navigateStories(
e.clientX > median
? 'next'
: 'prev')
})
document.addEventListener('keydown', ({key}) => {
if (key !== 'ArrowDown' || key !== 'ArrowUp')
navigateStories(
key === 'ArrowDown'
? 'next'
: 'prev')
})
短片故事導覽
現在來談談故事的獨特商業邏輯,以及他們所經歷的使用者體驗 名聞遐邇。這看起來很複雜又困難 您會發現它變得容易理解
我們會隱藏部分選取器,這有助於我們決定是否要捲動至 或顯示/隱藏故事。由於 HTML 是我們處理的位置 查詢該圖片,尋找好友 (使用者) 或故事 (故事)。
這些變數有助於我們回答以下這類問題: 是想從這位朋友分享另一個故事,還是要跟其他朋友分享?我是透過 藉此觸及家長和孩子的孩子
將以下程式碼新增至 app/js/index.js
的底部:
const navigateStories = direction => {
const story = state.current_story
const lastItemInUserStory = story.parentNode.firstElementChild
const firstItemInUserStory = story.parentNode.lastElementChild
const hasNextUserStory = story.parentElement.nextElementSibling
const hasPrevUserStory = story.parentElement.previousElementSibling
}
以下是盡可能貼近自然用語的商業邏輯目標:
- 決定輕觸的處理方式
- 如果有下一則/上一篇故事:顯示該故事
- 如果是朋友最近一次/第一個故事:向新朋友展示
- 如果沒有要指向這個方向的故事,則不執行任何動作
- 將目前的最新報導儲存至「
state
」
將醒目顯示的程式碼新增至 navigateStories
函式:
const navigateStories = direction => {
const story = state.current_story
const lastItemInUserStory = story.parentNode.firstElementChild
const firstItemInUserStory = story.parentNode.lastElementChild
const hasNextUserStory = story.parentElement.nextElementSibling
const hasPrevUserStory = story.parentElement.previousElementSibling
if (direction === 'next') {
if (lastItemInUserStory === story && !hasNextUserStory)
return
else if (lastItemInUserStory === story && hasNextUserStory) {
state.current_story = story.parentElement.nextElementSibling.lastElementChild
story.parentElement.nextElementSibling.scrollIntoView({
behavior: 'smooth'
})
}
else {
story.classList.add('seen')
state.current_story = story.previousElementSibling
}
}
else if(direction === 'prev') {
if (firstItemInUserStory === story && !hasPrevUserStory)
return
else if (firstItemInUserStory === story && hasPrevUserStory) {
state.current_story = story.parentElement.previousElementSibling.firstElementChild
story.parentElement.previousElementSibling.scrollIntoView({
behavior: 'smooth'
})
}
else {
story.nextElementSibling.classList.remove('seen')
state.current_story = story.nextElementSibling
}
}
}
立即試用
- 如要預覽網站,請按下「查看應用程式」。然後按下
全螢幕
。
結論
以上就是使用元件的需求。歡迎建立 並使用資料推動資料,而且通常成為您自己專屬的功能!