ساخت کامپوننت تایملاین با React — از صفر تا صد

۹۹ بازدید
آخرین به‌روزرسانی: ۱۹ شهریور ۱۴۰۲
زمان مطالعه: ۶ دقیقه
ساخت کامپوننت تایملاین با React — از صفر تا صد

کامپوننت تایملاین جزو قابلیت‌هایی است که در انواع بسیار مختلفی از وب‌سایت‌ها ممکن است به کار آید. بنابراین اگر تاکنون علاقه‌مند بوده‌اید که یک تایملاین در وب‌سایت خود داشته باشید، با ما تا انتهای این راهنما همراه باشید تا با مراحل عملی ساخت کامپوننت تایملاین با React آشنا شوید.

برخی از دلایلی که ممکن است بخواهید چنین کامپوننتی داشته باشید احتمالاً شامل موارد فهرست زیر هستند:

  • در آینده به این تایملاین نگاه کنید و متوجه شوید که در چه موقعیت زمانی چه انگیزه‌هایی داشته‌اید. موفقیت یک سفر است و نه یک مقصد و باید همه اهداف خود را در مسیر رسیدن به موفقیت بنویسیم.
  • چنین کامپوننتی می‌تواند به جذب مشتریان بیشتر کمک کند.
  • تایملاین نوع متفاوتی از پورتفولیو و در واقع نوع منحصر به فردی از آن محسوب می‌شود.

در ادامه با مراحل ساخت چنین کامپوننتی آشنا می‌شویم.

ساخت کامپوننت تایملاین با React

در تصویر فوق آن چه را که در این مقاله می‌خواهیم با ری‌اکت بسازیم، می‌بینید. پیش از آغاز مراحل کار را تقسیم‌بندی می‌کنیم:

  1. یک data ایجاد می‌کنیم که مورد نیاز خواهد بود.
  2. کامپوننت TimelineItem را که هر مدخل منفرد تایملاین را شامل می‌شود می‌سازیم.
  3. یک کانتینر Timeline را می‌سازیم که data ارسالی را گرفته و به TimelineItem می‌فرستد.
  4. همه موارد فوق را استایل‌بندی می‌کنیم.

ایجاد data

پیش از ایجاد عملی کامپوننت‌های ری‌اکت باید بدانیم که دقیقاً چه نوع داده‌ای قرار است در آن‌ها ببینیم تا بتوانیم ساختار DOM را برنامه‌ریزی کنیم.

در این اپلیکیشن تایملاین باید یک آرایه از اشیا داشته باشیم. این آرایه را timelineData می‌نامیم. کد آن به صورت زیر است:

1[
2    {
3        text: 'Wrote my first blog post ever on Medium',
4        date: 'March 03 2017',
5        category: {
6            tag: 'medium',
7            color: '#018f69'
8        },
9        link: {
10            url:
11                'https://medium.com/@popflorin1705/javascript-coding-challenge-1-6d9c712963d2',
12            text: 'Read more'
13        }
14    },
15    {
16        // Another object with data
17    }
18];

مشخصه‌های آن کاملاً سرراست هستند. از data مشابهی که روی صفحه تایملاین داریم استفاده کرده‌ایم تا بتوانیم آن را عملیاتی بسازیم.

در مرحله بعد کامپوننت TimelineItem را ایجاد می‌کنیم. این کامپوننت از آن data استفاده می‌کند که شیء فوق می‌فرستد:

کامپوننت TimelineItem

1const TimelineItem = ({ data }) => (
2    <div className="timeline-item">
3        <div className="timeline-item-content">
4            <span className="tag" style={{ background: data.category.color }}>
5                {data.category.tag}
6            </span>
7            <time>{data.date}</time>
8            <p>{data.text}</p>
9            {data.link && (
10                <a
11                    href={data.link.url}
12                    target="_blank"
13                    rel="noopener noreferrer"
14                >
15                    {data.link.text}
16                </a>
17            )}
18            <span className="circle" />
19        </div>
20    </div>
21);

در این کامپوننت با تگ‌های زیر مواجه هستیم:

  1. یک div به نام timeline-item. – به عنوان یک پوشش (Wrapper) استفاده می‌شود. این div نیمی از عرض والد خود را دارد (50%) و هر div به صورت timeline-item. با استفاده از سلکتور nth-child(odd): در سمت راست قرار می‌گیرد.
  2. یک Div به نام timeline-item-content. – این نیز یک پوشش دیگر است. در مورد علت وجود آن در بخش استایل‌بندی بیشتر توضیح می‌دهیم.
  3. یک span به نام tag. – این تگ بسته به دسته‌بندی یک رنگ پس‌زمینه سفارشی دارد.
  4. تگ‌های time/date و text
  5. تگ Link – باید بررسی کنیم آیا link عرضه شده است یا نه، زیرا ممکن است همواره چنین چیزی نداشته باشیم.
  6. یک span به نام circle. – این تگ برای قرار دادن یک دایره روی میانه خط/نوار استفاده می‌شود.

نکته: زمانی که به بخش استایل‌بندی/CSS برسیم همه این موارد معنی بیشتری پیدا می‌کنند، اما پیش از آن باید کامپوننت Timeline را ایجاد کنیم.

کانتینر Timeline

این کامپوننت اساساً یک map روی آرایه است و برای هر شیء یک کامپوننت TimelineItem می‌سازد. همچنین یک بررسی انجام می‌دهیم تا مطمئن شویم که دست کم یک عنصر در آرایه وجود داشته باشد:

1import timelineData from '_path_to_file_';
2
3const Timeline = () =>
4    timelineData.length > 0 && (
5        <div className="timeline-container">
6            {timelineData.map((data, idx) => (
7                <TimelineItem data={data} key={idx} />
8            ))}
9        </div>
10    );

چنان که پیش‌تر اشاره کردیم، timelineData آرایه‌ای از اشیا است که شامل همه اطلاعات مورد نیاز است. در این مورد این آرایه را در یک فایل ذخیره کرده‌ایم و آن را در اینجا ایمپورت کرده‌ایم، اما آن را می‌توان از یک پایگاه داده یا از یک API نیز دریافت کرد. همه چیز به چارچوب کاری شما وابسته است.

CSS

اغلب پوشش‌هایی که تعریف می‌کنیم در کانتینرهای felxbox قرار دارند، زیرا به روش آسان‌تری می‌توانیم با موقعیت آن‌ها بازی کنیم. کار خود را با CSS مربوط به timeline-container. آغاز می‌کنیم:

1.timeline-container {
2    display: flex;
3    flex-direction: column;
4    position: relative;
5    margin: 40px 0;
6}
7
8.timeline-container::after {
9    background-color: #e17b77;
10    content: '';
11    position: absolute;
12    left: calc(50% - 2px);
13    width: 4px;
14    height: 100%;
15}

در کد فوق از سلکتور after:: برای ایجاد آن نوار/خط قرمز در میانه timeline-container. استفاده می‌کنیم. با استفاده از تابع ()calc می‌توانیم خط را دقیقاً در میانه آن قرار دهیم و نیمی از اندازه آن (2 پیکسل) را از 50% کم کنیم. دلیل نیاز به انجام این کار آن است که به صورت پیش‌فرض مشخصه left بر اساس لبه چپ یک عنصر و نه میانه آن تنظیم می‌شود.

اکنون به بررسی پوشش timeline-item. می‌پردازیم. در ادامه می‌توانید نمونه‌ای از شیوه قرارگیری آن را درون والدش (timeline-container.) ببیند. با توجه به مقاصد آموزشی این مقاله یک حاشیه به این پوشش‌ها اضافه کردیم تا هایلایت شوند.

ساخت کامپوننت تایملاین با React

چنان که می‌بینید هر پوشش به سمت راست می‌رود و پوشش داخلی یعنی.timeline-item-content فضای کمتری اشغال می‌کند. فضای ایجاد شده با تگ p است که (غالباً) درون آن قرار دارد. در ادامه CSS آن را می‌نویسیم:

1.timeline-item {
2    display: flex;
3    justify-content: flex-end;
4    padding-right: 30px;
5    position: relative;
6    margin: 10px 0;
7    width: 50%;
8}
9
10.timeline-item:nth-child(odd) {
11    align-self: flex-end;
12    justify-content: flex-start;
13    padding-left: 30px;
14    padding-right: 0;
15}

نکته کلیدی کد فوق این است که از سلکتور nth-child(odd): استفاده می‌کنیم و مشخصه align-self را روی flex-end تعیین می‌کنیم. معنی آن این است که باید تا حد امکان به سمت راست برود.

از آنجا که این پوشش‌ها 50% عرض را دارند، هر دوی آن‌ها با هم کل عرض را اشغال می‌کنند. از اینجا به بعد هر بار که بخواهیم چیزی را در سمت راست به صورت متفاوت استایل‌بندی کنیم، از همین رویکرد استفاده خواهیم کرد. در ادامه کد CSS پوشش timeline-item-content. را می‌نویسیم:

1.timeline-item-content {
2    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
3    border-radius: 5px;
4    background-color: #fff;
5    display: flex;
6    flex-direction: column;
7    align-items: flex-end;
8    padding: 15px;
9    position: relative;
10    width: 400px;
11    max-width: 70%;
12    text-align: right;
13}
14
15.timeline-item-content::after {
16    content: ' ';
17    background-color: #fff;
18    box-shadow: 1px -1px 1px rgba(0, 0, 0, 0.2);
19    position: absolute;
20    right: -7.5px;
21    top: calc(50% - 7.5px);
22    transform: rotate(45deg);
23    width: 15px;
24    height: 15px;
25}
26
27.timeline-item:nth-child(odd) .timeline-item-content {
28    text-align: left;
29    align-items: flex-start;
30}
31
32.timeline-item:nth-child(odd) .timeline-item-content::after {
33    right: auto;
34    left: -7.5px;
35    box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.2);
36}

موارد زیر در کد فوق قابل توضیح هستند:

  1. این پوشش دارای یک width ثابت و یک max-width است. دلیل این امر آن است که می‌خواهیم نوعی کران داشته باشیم، یعنی می‌خواهیم در صورتی که تعداد کلمات کم بود، عرض باکس دست کم برابر با 400px داشته باشید، اما اگر متن از آن بیشتر شد، نباید کل فضا یعنی 50% از پوشش timeline-item. را اشغال کند، بلکه باید متن به سمت خط بعدی حرکت کند. به همین دلیل است که از پوشش timeline-item-content. بهره گرفته‌ایم.
  2. مشخصه‌های text-align و align-items برای هل دادن عناصر درونی به سمت چپ و راست بسته به والد استفاده می‌شوند.
  3. فلش کوچکی که به خط میانی اشاره می‌کند، از سوی استایل‌های اعمال شده روی سلکتور after:: ارائه شده است. اساساً این یک باکس با box-shadow است که 45 درجه چرخیده است.
  4. همان طور که پیش‌تر اشاره شد، سمت راست با انتخاب کردن والد با استفاده از سلکتور nth-child(odd): استایل‌بندی می‌شود.
  5. در بخش بعدی همه عناصر درونی را استایل‌بندی می‌کنیم:
1.timeline-item-content .tag {
2    color: #fff;
3    font-size: 12px;
4    font-weight: bold;
5    top: 5px;
6    left: 5px;
7    letter-spacing: 1px;
8    padding: 5px;
9    position: absolute;
10    text-transform: uppercase;
11}
12
13.timeline-item:nth-child(odd) .timeline-item-content .tag {
14    left: auto;
15    right: 5px;
16}
17
18.timeline-item-content time {
19    color: #777;
20    font-size: 12px;
21    font-weight: bold;
22}
23
24.timeline-item-content p {
25    font-size: 16px;
26    line-height: 24px;
27    margin: 15px 0;
28    max-width: 250px;
29}
30
31.timeline-item-content a {
32    font-size: 14px;
33    font-weight: bold;
34}
35
36.timeline-item-content a::after {
37    content: ' ►';
38    font-size: 12px;
39}
40
41.timeline-item-content .circle {
42    background-color: #fff;
43    border: 3px solid #e17b77;
44    border-radius: 50%;
45    position: absolute;
46    top: calc(50% - 10px);
47    right: -40px;
48    width: 20px;
49    height: 20px;
50    z-index: 100;
51}
52
53.timeline-item:nth-child(odd) .timeline-item-content .circle {
54    right: auto;
55    left: -40px;
56}

در این کد چند نکته وجود دارند که باید به آن‌ها اشاره کنیم:

  1. همچنان که احتمالاً حدس می‌زنید،tag. موقعیتی به صورت absolute دارد، زیرا می‌خواهیم صرف‌نظر از اندازه باکس، آن را همیشه در سمت چپ یا راست نگه داریم.
  2. باید یک دایره کوچک پس از تگ a اضافه کنیم تا مشخص شود که لینک است.
  3. یک circle. ایجاد کرده و آن را روی میانه خط/نوار و مستقیماً در جلوی فلش قرار می‌دهیم.

اینک کار تقریباً تمام شده است. تنها کاری که مانده است، افزودن CSS است تا همه چیز در تمام اندازه‌های مختلف صفحه‌ها واکنش‌گرا شود:

1@media only screen and (max-width: 1023px) {
2    .timeline-item-content {
3        max-width: 100%;
4    }
5}
6
7@media only screen and (max-width: 767px) {
8    .timeline-item-content,
9    .timeline-item:nth-child(odd) .timeline-item-content {
10        padding: 15px 10px;
11        text-align: center;
12        align-items: center;
13    }
14    
15    .timeline-item-content .tag {
16        width: calc(100% - 10px);
17        text-align: center;
18    }
19    
20    .timeline-item-content time {
21        margin-top: 20px;
22    }
23    
24    .timeline-item-content a {
25        text-decoration: underline;
26    }
27    
28    .timeline-item-content a::after {
29        display: none;
30    }
31}

در کد فوق دو کوئری مدیا انجام می‌دهیم:

  1. روی اندازه‌های صفحه کوچک یعنی زمانی که max-width: 1023px است، باید به timeline-item-content. اجازه بدهیم که کل عرض والدش را پر کند، زیرا صفحه کوچک‌تر است. در غیر این صورت ممکن است فشرده به نظر برسد.
  2. در روی گوشی‌ها یعنی زمانی که max-width: 767px است، شرایط زیر برقرار است:
  3. tag. روی width کامل تعیین می‌شود. به همین جهت باید 10px را از کل 100% کسر کنیم. زیرا باید آن را در موقعیت left: 5px قرار دهیم و از این رو باید دو برابر این مقدار را کم کنیم.
  4. همه متن‌ها را به صورت وسط‌چین قرار می‌دهیم و کمی از سمت بالا به سمت پایین می‌بریم.
  5. Caret لینک را حذف کرده و یک زیرخط اضافه می‌کنیم تا روی موبایل بهتر دیده شود.

سخن پایانی

به این ترتیب در این راهنما موفق شدیم یک کامپوننت تایملاین با ری‌اکت بسازیم.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freecodecamp
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *