分享 46 3

    使用 NeoDB API 构建观影页面

    AI摘要:DeepSeek AI摘要 DeepSeek
    本文介绍了如何使用NeoDB API构建观影页面。首先,通过Mastodon账号登录NeoDB并生成API token。接着,使用NeoDB Shelf API项目部署在Vercel上,并通过JavaScript代码实现页面数据的动态加载和展示。文章还提供了相关的CSS样式和HTML结构,帮助用户快速搭建一个功能完善的观影页面。

    前言

    使用 neodb.social 的API算是多一种选择.
    豆瓣数据的获取还是不太方便

    获取neodb的token

    使用mastodon账号登录 https://neodb.social/
    在右上角头像点击- 设置 - 找到更多设置
    2024-12-26T00:09:57.png
    点击 查看已授权的应用程序

    2024-12-26T00:11:01.png
    生成一个token即可

    获取neodb API

    在此使用项目
    https://github.com/Lyunvy/neodb-shelf-api

    可以部署在vercel上,过程就不赘述了

    调用

    在本主题的基础上修改

    JS

    class NeoDB {
        constructor(config) {
            this.container = config.container;
            this.types = config.types ?? ["book", "movie", "tv", "music", "game", "podcast"];
            this.baseAPI = config.baseAPI;
            this.type = "movie";
            this.status = "complete";
            this.finished = false;
            this.paged = 1;
            this.subjects = [];
            this._create();
        }
    
        on(event, element, callback) {
            const nodeList = document.querySelectorAll(element);
            nodeList.forEach((item) => {
                item.addEventListener(event, callback);
            });
        }
    
        _handleTypeClick() {
            this.on("click", ".neodb-navItem", (t) => {
                const self = t.currentTarget;
                if (self.classList.contains("current")) return;
                this.type = self.dataset.type;
                document.querySelector(".neodb-list").innerHTML = "";
                document.querySelector(".lds-ripple").classList.remove("u-hide");
                document.querySelector(".neodb-navItem.current").classList.remove("current");
                self.classList.add("current");
                this.paged = 1;
                this.finished = false;
                this.subjects = [];
                this._fetchData();
            });
        }
    
        _renderTypes() {
            document.querySelector(".neodb-nav").innerHTML = this.types
                .map((item) => {
                    return `<span class="neodb-navItem${
                        this.type == item ? " current" : ""
                    }" data-type="${item}">${item}</span>`;
                })
                .join("");
            this._handleTypeClick();
        }
    
        _fetchData() {
            const params = new URLSearchParams({
                type: "complete",
                category: this.type,
                page: this.paged.toString(),
            });
        
            return fetch(this.baseAPI + "?" + params.toString())
                .then((response) => response.json())
                .then((data) => {
                    if (data.length) {
                        // 过滤重复项
                        data = data.filter(item => !this.subjects.some(existing => existing.item.id === item.item.id));
                        
                        if (data.length) {
                            this.subjects = [...this.subjects, ...data];
                            this._renderListTemplate();
                        }
        
                        document.querySelector(".lds-ripple").classList.add("u-hide");
                    } else {
                        this.finished = true; // 没有更多数据
                        document.querySelector(".lds-ripple").classList.add("u-hide");
                    }
                });
        }
    
        _renderListTemplate() {
            document.querySelector(".neodb-list").innerHTML = this.subjects
                .map((item) => {
                    const coverImage = item.item.cover_image_url;
                    const title = item.item.title;
                    const rating = item.item.rating;
                    const link = item.item.id;
    
                    return `<div class="neodb-item">
                        <img src="${coverImage}" referrerpolicy="no-referrer" class="neodb-image">
                        <div class="neodb-score">
                            ${rating ? `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>${rating}` : ""}
                        </div>
                        <div class="neodb-title">
                            <a href="${link}" target="_blank">${title}</a>
                        </div>
                        
                    </div>`;
                })
                .join("");
        }
    
        _handleScroll() {
            let isLoading = false; // 标志位,表示是否正在加载数据
            let lastScrollTop = 0; // 上一次的滚动位置
        
            window.addEventListener("scroll", () => {
                const scrollY = window.scrollY || window.pageYOffset;
                const moreElement = document.querySelector(".block-more");
        
                // 检查滚动到底部的条件
                if (
                    moreElement.offsetTop + moreElement.clientHeight <= scrollY + window.innerHeight &&
                    document.querySelector(".lds-ripple").classList.contains("u-hide") &&
                    !this.finished &&
                    !isLoading // 确保没有正在加载数据
                ) {
                    isLoading = true; // 设置标志位为 true,表示正在加载数据
                    document.querySelector(".lds-ripple").classList.remove("u-hide");
                    this.paged++;
                    this._fetchData().finally(() => {
                        isLoading = false; // 数据加载完成后,重置标志位
                    });
                }
        
                // 更新上一次的滚动位置
                lastScrollTop = scrollY;
            });
        }
    
        _create() {
            if (document.querySelector(".neodb-container")) {
                const container = document.querySelector(this.container);
                if (!container) return;
                container.innerHTML = `
                    <nav class="neodb-nav"></nav>
                    <div class="neodb-list"></div>
                    <div class="block-more block-more__centered">
                        <div class="lds-ripple"></div>
                    </div>
                `;
                this._renderTypes();
                this._fetchData();
                this._handleScroll();
            }
        }
    }
    

    CSS

    .neodb-container{--db-item-width:150px;--db-item-height:180px;--db-music-width:150px;--db-music-height:150px;--db-primary-color:var(--farallon-hover-color);--db-background-white:var(--farallon-background-white);--db-background-gray:var(--farallon-background-gray);--db-border-color:var(--farallon-border-color);--db-text-light:var(--farallon-text-light);}.neodb-nav{padding:30px 0 20px;display:flex;align-items:center;flex-wrap:wrap;}.neodb-navItem{font-size:20px;cursor:pointer;border-bottom:1px solid rgba(0,0,0,0);transition:0.5s border-color;display:flex;align-items:center;text-transform:capitalize;}.neodb-navItem.current,.neodb-navItem:hover{border-color:inherit;}.neodb-navItem{margin-right:20px;}.neodb-score svg{fill:#f5c518;margin-right:5px;}.neodb-list{display:flex;align-items:flex-start;flex-wrap:wrap;}.neodb-image{width:var(--db-item-width);height:var(--db-item-height);object-fit:cover;border-radius:4px;}.neodb-image:hover{box-shadow:0 0 10px var(--db-border-color);}.neodb-title{margin-top:2px;font-size:14px;line-height:1.4;}.neodb-title a:hover{color:var(--db-primary-color);text-decoration:underline;}.neodb-genreItem{background:var(--db-background-gray);font-size:12px;padding:5px 12px;border-radius:4px;margin-right:6px;margin-bottom:10px;line-height:1.4;cursor:pointer;}.neodb-genreItem.is-active,.neodb-genreItem:hover{background-color:var(--db-primary-color);color:var(--db-background-white);}.neodb-genres{padding-bottom:15px;display:flex;flex-wrap:wrap;}.neodb-genres.u-hide + .neodb-list{padding-top:10px;}.neodb-score{display:flex;align-items:center;font-size:14px;color:var(--db-text-light);}.neodb-item{width:var(--db-item-width);margin-right:20px;margin-bottom:20px;position:relative;}.neodb-item__music img{width:var(--db-music-width);height:var(--db-music-height);object-fit:cover;}.neodb-date{position:relative;font-size:20px;color:var(--farallon-text-light);font-weight:900;line-height:1;}.neodb-date::before{content:"";position:absolute;top:0.5em;bottom:-2px;left:-10px;width:3.4em;z-index:-1;background:var(--farallon-hover-color);opacity:0.3;transform:skew(-35deg);transition:opacity 0.2s ease;border-radius:3px 8px 10px 6px;}.neodb-date{margin-top:30px;margin-bottom:10px;}.neodb-dateList{padding-left:15px;padding-top:5px;padding-right:15px;}.neodb-card__list{display:flex;align-items:center;padding:15px 0;border-bottom:1px dotted var(--farallon-border-color);font-size:14px;color:rgba(0,0,0,0.55);}.neodb-card__list:last-child{border-bottom:0;}.neodb-card__list .title{font-size:18px;margin-bottom:5px;}.neodb-card__list .rating{margin:0 0 0px;font-size:14px;line-height:1;display:flex;align-items:center;}.neodb-card__list .rating .allstardark{position:relative;color:#f99b01;height:16px;width:80px;background-repeat:repeat;background-image:url("../images/star.svg");background-size:auto 100%;margin-right:5px;}.neodb-card__list .rating .allstarlight{position:absolute;left:0;color:#f99b01;height:16px;overflow:hidden;background-repeat:repeat;background-image:url("../images/star-fill.svg");background-size:auto 100%;}.neodb-card__list img{width:80px;border-radius:4px;height:80px;object-fit:cover;flex:0 0 auto;margin-right:15px;}.neodb-titleDate{display:flex;flex-direction:column;line-height:1.1;margin-bottom:10px;flex:0 0 auto;margin-right:15px;align-items:center;}.neodb-titleDate__day{font-weight:900;font-size:44px;}.neodb-titleDate__month{font-size:14px;color:var(--farallon-text-light);font-weight:900;}.neodb-list__card{display:block;}.neodb-dateList__card{display:flex;flex-wrap:wrap;align-items:flex-start;}.neodb-listBydate{display:flex;align-items:flex-start;margin-top:15px;}@media (max-width:600px){.neodb-listBydate{flex-direction:column;}}

    HTML

        <div class="neodb-container"></div>
    <script>
    const neodb = new NeoDB({
        container: ".neodb-container",
        baseAPI: "https://neodb.imsun.org/api",
        types: ["book", "movie", "tv", "music", "game"],
    });    
    </script>

    其中https://neodb.imsun.org/为 部署在 vercel 的绑定域名,可自行更改

    1. bigfa

      bigfa

      2024-12-27 17:04
      香港 Kowloon City 九龙城

      这不是拿我的魔改的 😂

        1. 老孙

          2024-12-27 17:19
          新加坡 淡馬錫
          @bigfa

          不得不说大佬的作品就是优秀~

        2. 老孙

          2024-12-27 17:10
          新加坡 淡馬錫
          @bigfa

          是的啊 就是一毛一样.😂