Codelab: Hikayeler bileşeni oluşturma

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

  1. Projeyi düzenlenebilir hale getirmek için Düzenlemek için Remiks'i tıklayın.
  2. 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> üzerindeki style ö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
Izgara sütununun taşmasını ve yatay bir kaydırıcıyı gösteren Chrome Geliştirici Araçları.

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 önler
  • touch-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 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.