Bu codelab'de, Instagram Hikayeleri gibi bir deneyimi nasıl oluşturacağınızı öğrenebilirsiniz. hale getirir. Bileşeni HTML, ardından CSS ile başlayarak derleyeceğiz, ardından JavaScript'i seçin.
Hikayeler bileşeni oluşturma başlıklı blog yayınıma göz atın. bölümüne göz atın.
Kurulum
- Projeyi düzenlenebilir hale getirmek için Düzenlemek için Remiks'i tıklayın.
app/index.html
adlı kişiyi aç.
HTML
Her zaman anlamsal HTML kullanmayı hedefliyorum.
Her arkadaşın çok sayıda öyküsü olabilir. Bu yüzden, tek bir arkadaşım için
Her arkadaş için <section>
ve her hikaye için <article>
öğesi.
Hadi baştan başlayalım. İlk olarak, işletmemiz için bir kapsayıcıya
haber bileşeni.
<body>
için bir <div>
öğesi ekleyin:
<div class="stories">
</div>
Arkadaşlarınızı temsil edecek birkaç <section>
öğesi ekleyin:
<div class="stories">
<section class="user"></section>
<section class="user"></section>
<section class="user"></section>
<section class="user"></section>
</div>
Haberleri temsil edecek birkaç <article>
öğesi ekleyin:
<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>
- Hikayelerin prototipini oluşturmak için bir resim hizmeti (
picsum.com
) kullanıyoruz. - Her
<article>
üzerindekistyle
özelliği, yer tutucu yükleme işleminin bir parçasıdır. daha fazla bilgi edineceksiniz.
CSS
İçeriğimiz her zaman şık bir içerik sunar. Hadi bu kemikleri insanların anlayacağı bir şekilde ön plana çıkarmanıza yardımcı olabilir. Bugün mobil öncelikli çalışmaya başlayacağız.
.stories
<div class="stories">
kapsayıcımız için yatay bir kaydırma kapsayıcısı istiyoruz.
Bunu başarmak için:
- Kapsayıcıyı Izgara yapma
- Her alt öğeyi satır kanalını dolduracak şekilde ayarlama
- Her alt öğenin genişliğini mobil cihaz görüntü alanının genişliği kadar yapmak
Izgara, önceki sütunun sağına 100vw
genişliğinde yeni sütunlar yerleştirmeye devam eder
tıklayın.
![Chrome ve Geliştirici Araçları, tam genişlikte düzeni gösteren bir ızgara görseliyle açılır](https://web.developers.google.cn/static/articles/codelab-building-a-stories-component/image/chrome-devtools-open-a-72aaa3c91f873.png?authuser=5&hl=tr)
Aşağıdaki CSS'yi app/css/index.css
sayfasının alt kısmına ekleyin:
.stories {
display: grid;
grid: 1fr / auto-flow 100%;
gap: 1ch;
}
.
Artık görüntü alanının ötesine geçen içeriğe sahip olduğumuza göre,
ele alacağız. Vurgulanan kod satırlarını .stories
kural grubunuza ekleyin:
.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;
}
Yatay kaydırma istediğimiz için overflow-x
öğesini şuna ayarlayacağız:
auto
. Kullanıcı sayfayı kaydırdığında bileşenin yavaşça bir sonraki hikayeye devam etmesini isteriz.
Bu nedenle scroll-snap-type: x mandatory
kullanacağız. Bu konu hakkında daha fazla bilgi edinin
CSS Kaydırma Tutturma Noktaları'ndaki CSS
ve overscroll-davranışı
bazı bölümleri kapsıyor.
Kaydırma yapmayı kabul etmeleri hem üst kapsayıcının hem de alt öğelerin
bu konuyu artık ele alalım. app/css/index.css
öğesinin altına şu kodu ekleyin:
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
}
Uygulamanız henüz çalışmıyor ancak aşağıdaki videoda
scroll-snap-type
etkinleştirildi ve devre dışı bırakıldı. Etkinleştirildiğinde, her yatay
bir sonraki hikayeye kaydırın. Devre dışı bırakıldığında, tarayıcı
varsayılan kaydırma davranışı.
Bu sayede arkadaşlarınıza göz atabilirsiniz ancak sorun yaşamaya devam edeceğiz. anlatacağım.
.user
.user
bölümünde, bu alt hikayeyi işleyen bir düzen oluşturalım
emin olmanız gerekir. Bu sorunu çözmek için pratik bir yığın oluşturma ipucundan yararlanacağız.
Esas olarak, satır ve sütunun aynı Izgaraya sahip olduğu 1x1
takma adı [story]
ile başlamak ve her hikaye ızgarası öğesi,
ortaya çıkar.
Vurgulanan kodu .user
kural grubunuza ekleyin:
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
display: grid;
grid: [story] 1fr / [story] 1fr;
}
Aşağıdaki kural kümesini app/css/index.css
öğesinin altına ekleyin:
.story {
grid-area: story;
}
Artık mutlak konumlandırma, kayan öğeler veya diğer düzen yönergelerinin olup olmadığını sorabilirsiniz. Ayrıca, neredeyse hiç kod yok. Şuna bir bak! Bunun nedeni videoda ve blog yayınında daha ayrıntılı bir şekilde açıklanıyor.
.story
Şimdi sadece hikaye öğesinin stilini belirlememiz gerekiyor.
Daha önce, her <article>
öğesindeki style
özelliğinin
yer tutucu yükleme tekniği:
<article class="story" style="--bg: url(https://picsum.photos/480/840);"></article>
CSS'nin background-image
özelliğini kullanacağız. Bu özellik,
arka plan resmi kullanabilirsiniz. Kullanıcımızın bunu yapabilmesi için
resim üsttedir ve yükleme tamamlandığında otomatik olarak görüntülenir. Alıcı:
bunu etkinleştirdikten sonra, resim URL'mizi özel bir mülke (--bg
) yerleştirip
yükleme yer tutucusuyla katman yapmak için CSS'mizde.
İlk olarak .story
kural kümesini, bir renk geçişini arka plan resmiyle değiştirecek şekilde güncelleyelim
yükleme işlemini tamamladıktan sonra otomatik olarak gösterilir. Vurgulanan kodu .story
kural grubunuza ekleyin:
.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
değerinin cover
değerine ayarlanması, tabloda boş alan olmamasını sağlar
çünkü resmimiz dolduracak. 2 arka plan resmi tanımlanıyor
yükleme mezar taşı adı verilen düzgün bir CSS web hilesi çekmemizi sağlar:
- Arka plan resmi 1 (
var(--bg)
), HTML'de satır içi olarak ilettiğimiz URL'dir - Arka plan resmi 2 (
linear-gradient(to top, lch(98 0 0), lch(90 0 0))
bir gradyandır URL yüklenirken gösterilecek
Resmin indirilmesi tamamlandığında CSS, gradyanı otomatik olarak resimle değiştirir.
Ardından, bazı davranışları kaldırmak için biraz CSS ekleyeceğiz. Böylece tarayıcının daha hızlı hareket edebilmesi için serbest kalacaksınız.
Vurgulanan kodu .story
kural grubunuza ekleyin:
.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
, kullanıcıların metni yanlışlıkla seçmesini önlertouch-action: manipulation
, tarayıcıya bu etkileşimlerin Bu, tarayıcının dokunma etkinlikleri olarak görülmesini ve böylece tarayıcının bir URL'yi tıklayıp tıklamamaya karar verme
Son olarak, hikayeler arasındaki geçişi canlandırmak için küçük bir CSS ekleyelim. URL'yi
.story
kural kümenizde vurgulanan kod:
.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
sınıfı, çıkış gerektiren bir hikayeye eklenecek.
Özel yumuşak geçiş işlevini aldım (cubic-bezier(0.4, 0.0, 1,1)
)
Materyal Tasarım'ın Yumuşak Geçiş'ten
rehberine (Hızlandırılmış yumuşatma bölümüne kaydırın).
Dikkatli bir gözünüz varsa muhtemelen pointer-events: none
fark etmişsinizdir
şu anda kafanızı kazımışsınız. Bence en önemlisi bu
dezavantajımız var. Buna ihtiyacımız var çünkü bir .seen.story
öğesi
görünmezken bile dokunuş alacak.
pointer-events
none
, camdan hikayeyi pencereye dönüştürüyoruz ve
elde edebilirsiniz. Ödün vermek kadar fena değil, burada yönetmesi de çok zor değil
inceleyebilirsiniz. z-index
ile ilgilenmiyoruz. Bu konuda çok iyiyim
sabit.
JavaScript
Hikayeler bileşeninin etkileşimleri kullanıcı için oldukça basittir. İleri gitmek için sağa, geri gitmek için sola dokunun. Kullanıcılara yönelik basit şeyler genellikle çok çaba sarf edeceğim. Yine de büyük bir kısmını biz halledeceğiz.
Kurulum
Başlangıç olarak, mümkün olduğunca fazla bilgiyi hesaplayıp depolayalım.
Şu kodu app/js/index.js
alanına ekleyin:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
İlk JavaScript satırımız, birincil HTML kodumuza bir referans alır ve depolar öğe kökü. Sonraki satır, öğemizin orta kısmının nerede olduğunu hesaplar. Dolayısıyla, bir dokunuşun ileri veya geri gitmesine karar verebilir.
Eyalet
Daha sonra, mantığımızla ilgili bir duruma sahip küçük bir nesne oluşturuyoruz. Burada
yalnızca güncel hikayeyle ilgileniyoruz. HTML işaretlememizde
ilk arkadaşını ve son hikayesini öğrenerek ona erişebilir. Vurgulanan kodu ekleyin
app/js/index.js
cihazınıza eklendi:
const stories = document.querySelector('.stories')
const median = stories.offsetLeft + (stories.clientWidth / 2)
const state = {
current_story: stories.firstElementChild.lastElementChild
}
Dinleyiciler
Artık kullanıcı etkinliklerini dinlemeye ve yönlendirmeye başlamak için yeterli mantığımız var.
fare
Hikayeler kapsayıcımızdaki 'click'
etkinliğini dinleyerek başlayalım.
Vurgulanan kodu app/js/index.js
kampanyasına ekleyin:
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>
öğesine ait olmayan bir tıklama gerçekleşirse hiçbir işlem yapılmaz.
Konu bir makaleyse farenin veya parmağın yatay konumunu
clientX
navigateStories
özelliğini henüz uygulamadık ancak
hangi yönde ilerlememiz gerektiğini belirler. Söz konusu kullanıcı konumu
next
değerine gitmemiz gerektiğini biliyoruz, aksi takdirde
prev
(önceki).
Klavye
Şimdi klavye basmalarını dinleyelim. Aşağı ok tuşuna basarsanız
alıcı: next
. Yukarı Ok'u bulmak için prev
'ye gideceğiz.
Vurgulanan kodu app/js/index.js
kampanyasına ekleyin:
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')
})
Hikayeler'de gezinme
Hikayelerin benzersiz iş mantığını ve oluşturdukları kullanıcı deneyimini ele alma zamanı meşhurdur. Bu biraz karmaşık ve zor görünüyor, ancak bence bunu sıradan bir satıra alırsanız oldukça kolay anlaşılır olduğunu göreceksiniz.
En başta, sayfayı kaydırarak bir veya bir hikayeyi gösterebilir/gizleyebilir. Çalıştığımız yer HTML olduğu için veya hikayelerin (hikayeler) varlığını sorgulamak için kullanır.
Bu değişkenler, "x hikayesi için "sonraki", bu arkadaştan başka bir hikayeye mi geçelim?" ağacı kullanarak yaptım. anne babalara ve çocuklarına ulaşmayı başardık.
app/js/index.js
öğesinin altına şu kodu ekleyin:
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
}
İş mantığı hedefimiz, doğal dile mümkün olduğunca yakındır:
- Dokunmanın nasıl gerçekleştirileceğine karar verme
- Sonraki/önceki bir hikaye varsa: O hikayeyi gösterin
- Bu, arkadaşınızın son/ilk hikayesiyse: Yeni bir arkadaşınıza gösterin
- Bu yönde gidecek bir hikaye yoksa hiçbir şey yapmayın.
- Yeni mevcut hikayeyi
state
klasörüne sakla
Vurgulanan kodu navigateStories
işlevinize ekleyin:
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
}
}
}
Deneyin
- Siteyi önizlemek için Uygulamayı Görüntüle'ye basın. Ardından,
Tam ekran
.
Sonuç
Bu e-posta, bileşenle ilgili ihtiyaçlarımı özetlemiş oldu. Projeyi geliştirmekten kullanın, verilerle destekleyin ve genel olarak kendinize özel hale getirebilirsiniz.