惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
V
V2EX
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
T
Tailwind CSS Blog
Y
Y Combinator Blog
C
Check Point Blog
爱范儿
爱范儿
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
美团技术团队
雷峰网
雷峰网
IT之家
IT之家
WordPress大学
WordPress大学
V
Visual Studio Blog
Microsoft Azure Blog
Microsoft Azure Blog
MyScale Blog
MyScale Blog
N
News and Events Feed by Topic
罗磊的独立博客
S
SegmentFault 最新的问题
S
Security Affairs
aimingoo的专栏
aimingoo的专栏
F
Fortinet All Blogs
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Google DeepMind News
Google DeepMind News
B
Blog
O
OpenAI News
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
Hacker News: Ask HN
Hacker News: Ask HN
博客园_首页
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Help Net Security
Help Net Security
月光博客
月光博客
J
Java Code Geeks
L
LangChain Blog
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Apple Machine Learning Research
Apple Machine Learning Research
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

埃氮幂の命名空间

埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间 埃氮幂の命名空间
埃氮幂の命名空间
2026-02-14 · via 埃氮幂の命名空间

为什么迁移?

自从用Hexo建站以来,由于每次更新文章都要推仓库,等Vercel那边构建个几十秒,有时候网络环境不好,这就变成一项巨大的工程,看着群友纷纷(?好像也就几个吧)玩起了Next.js,我也有了去研究它的念头,正好可以掌握一个新的技术栈

但是没有使用HTML CSS JS许久并且没有用过React 和TS的我在这个项目面前还是太菜了。。。勉强做了一个导航栏就不知道怎么继续了。只好借鉴来Aria大佬的代码(多谢Aria),调一下颜色之类的,所以这个新博客和Aria的博客非常的像(可以说就是导航栏的位置和整个博客的配色不同)。

Aria之前已经写过一篇迁移小记了

前往以下网站,不保证安全性哦喵~新篇章:Next.js迁移小记Ariasaka

我记录一下改动的部分,其他的可以看Aria那篇。

修改

TimeLine外挂标签

我以前的Hexo站有个时间戳(站点历史)页,当时是用的butterfly主题带的时间线标签,然而我发现Aria没有做这个标签,于是我得自己动手了。

ts代码:

TS
"use client";
import { ReactElement } from "react";

export default function TimeLineTag({
  children,
  time,
  color,
}: {
  children: ReactElement[] | ReactElement;
  time: string;
  color?: string;
}) {
  
  return (
    <div className={`etag-timeline${color?" "+color:""}`}>
      <div className="timeline-item">
        <div className="timeline-item-title">
          <div className="item-circle">
            <p>{time}</p>
          </div>
        </div>
        <div className="timeline-item-content">
          {children}
        </div>
      </div>
    </div>
  );
}

css:

CSS
.etag-timeline {
    margin: 0 0 0px 10px;
    padding: 14px 20px 5px;
    border-left: 2px solid var(--timeline-color,#425aef)
}

.etag-timeline.blue {
    --timeline-color: #428bca;
    --timeline-bg: rgba(66,139,202, 0.2)
}

.etag-timeline.pink {
    --timeline-color: #ff69b4;
    --timeline-bg: rgba(255,105,180, 0.2)
}

.etag-timeline.red {
    --timeline-color: #f00;
    --timeline-bg: rgba(255,0,0, 0.2)
}

.etag-timeline.purple {
    --timeline-color: #6f42c1;
    --timeline-bg: rgba(111,66,193, 0.2)
}

.etag-timeline.orange {
    --timeline-color: #ff8c00;
    --timeline-bg: rgba(255,140,0, 0.2)
}

.etag-timeline.green {
    --timeline-color: #5cb85c;
    --timeline-bg: rgba(92,184,92, 0.2)
}

.etag-timeline .timeline-item {
    margin: 0 0 15px
}

.etag-timeline .timeline-item:hover .item-circle:before {
    border: 3px solid var(--admi-theme);
}


.etag-timeline .timeline-item .timeline-item-title {
    position: relative
}



.etag-timeline .timeline-item .item-circle:before {
    position: absolute;
    top: 50%;
    left: -27px;
    width: 6px;
    height: 6px;
    border: 3px solid var(--timeline-color,#425aef);
    border-radius: 50%;
    background: var(--admi-fontcolor);
    content: '';
    -webkit-transition: all .3s;
    -moz-transition: all .3s;
    -o-transition: all .3s;
    -ms-transition: all .3s;
    transition: all .3s;
    -webkit-transform: translate(0,-50%);
    -moz-transform: translate(0,-50%);
    -o-transform: translate(0,-50%);
    -ms-transform: translate(0,-50%); 
    transform: translate(0,-50%)
}

.etag-timeline .timeline-item .item-circle>p {
    margin: 0 0 8px;
    font-weight: 500
}

.etag-timeline .timeline-item .timeline-item-content {
    position: relative;
    padding: 12px 15px;
    border-radius: .5rem;
    border: 0.5px solid var(--admi-fontcolor);
    font-size: .93em
}

.etag-timeline .timeline-item .timeline-item-content>p {
    margin-top: 0;
}

.etag-timeline .timeline-item .timeline-item-content>:last-child {
    margin-bottom: 0
}

.etag-timeline+.timeline {
    margin-top: -20px
}

效果见时间戳

网址导航&时间戳

如你所见,网址导航这个就是复制的友链,时间戳后端和面板复制说说,前端用自己做的Timeline。

flink-check.jsonflink-circle.json

这两个都是ts生成的文件,分别给友链延时检测系统和朋友圈(Friend-Circle-Lite)提供友链信息

首页公告、友链公告、关于页等

这一堆Aria都是直接写了个mdx存在前端,但是我想尽量减少推仓库,于是多开了几个Vditor支持了在后端修改。不过发现Vditor有个问题就是不能在同一个页面显示多个Vditor,于是我只好加了按钮切换。

颜色模式

Aria的前端颜色模式是跟随浏览器的,想换必须改浏览器的设置,我想还是改成手动的比较好。但是这就涉及到一个组件向另一个隔了好几层的组件传递信息。Aria说可以用Context。

createContext()建一个Context:

TS
export declare interface Settings{
    colorMode:"light" | "dark"
}
export const defaultSettings:Settings={
    colorMode:"light"
};
export const SettingsContext = createContext({
    settings: defaultSettings,
    setSettings: (settings: Settings) => {}
});

然后在根布局中使用它:

TS
import { defaultSettings,getSettings,SettingsContext } from "@/utils/settings";
//其他引入

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  // 其他内容
  return (
    <html lang="zh-cn" data-theme={settings.colorMode}>
      //其他内容
      <body>
        <style>{`#out-aplayer{position:fixed;left:10000px}`}</style>
        <SettingsContext.Provider value={{settings,setSettings}}>
          //需要用到value属性内容的组件都放里面
        </SettingsContext.Provider>
      </body>
    </html>
  );
}

使用Context的值:

TS
const {settings,setSettings}=useContext(SettingsContext);

音乐

这个本来准备也支持后端改的(可以把不同平台的歌放一起组成一个歌单)但后来发现网易和酷狗都用不了只有QQ音乐可以用于是就省去这个了,直接在QQ音乐那边编辑歌单。

(不知道为什么被这一点工作硬控了半天)

组件

注意文件后缀是jsx

JS
"use client";
import { useEffect } from "react";

import '@/styles/APlayer.css';




export default function AplayerBase({
    data
}
) {
    useEffect(() => {
        const Aplayer=require("aplayer/dist/APlayer.min");
        window.aplayer = data?
            (new Aplayer({
                container: document.getElementById("aplayer"),
                fixed: false,
                autoplay: false,
                lrcType: 3,
                listMaxHeight: 20,
                audio: data.map((item,index)=>
                    ({
                        name: item.name || item.title || 'Audio name',
                        artist: item.artist || item.author || 'Audio artist',
                        url: item.url,
                        cover: item.cover || item.pic,
                        lrc: item.lrc || item.lyric || '',
                        type: item.type || 'auto',
                    })
                )
            }))
        :undefined;
    },[data]);
    return (
        <>
        </>
    );

}

放入根layout中

TS
"use client";
//...
import AplayerBase from "@/components/thirdpartyjs/Aplayer";
import { MusicInfo } from "@/interfaces/music";
import { getPlayListInfo } from "@/utils/metingbase"; 

process.env.TZ = "Asia/Shanghai";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const [settings,setSettings]=useState<Settings>(defaultSettings);
  const [musicData,setMusicData]=useState<MusicInfo[]>();
  const playerRef=useRef<HTMLElement>();
  //...
  useEffect(()=>{(async()=>{
    setMusicData(await getPlayListInfo("tencent","9307834870"));
  })()},[])
  return (
    <html lang="zh-cn" data-theme={settings.colorMode}>
      //...
      <body>
        <style>{`#out-aplayer{position:fixed;left:10000px}`}</style>
        <SettingsContext.Provider value={{settings,setSettings}}>
          //...
          <div id="out-aplayer">
          <div id="aplayer"></div>
          </div>
          <AplayerBase data={musicData}/>
        </SettingsContext.Provider>
      </body>
    </html>
  );
}

获取音乐信息

刚开始用的是Meting暴露的一些函数,但是发现网易那边本地测试可以获取到但是部署上去之后就获取不到了,去看了MetingJS发现用的是作者Meto的api,于是后来改成直接获取歌单的时候也用它了

TS
export async function getPlayListInfo(platform: string,id: string):Promise<MusicInfo[]>{
    try{
        let result: MusicInfo[]=[{
            type: "error",
            url: ""
        }];
        const url="https://api.i-meto.com/meting/api?server="+platform+"&type=playlist&id="+id+"&r=0.122";
        await fetch(url,{next: { revalidate: 7200, tags: ["music"] }}).then(async(res) => res.ok ? (await res.json()): {})
        .then((data)=>{result=data;});
        return result;
    }catch(e: any){
        return [{
            type: "error",
            url: e
        }];
    }
}

页面切换调整Aplayer位置

打开音乐厅的时候要把隐藏的aplayer显示出来

音乐厅里放一个id为musicpage-aplayer<div>

然后再根layout里建一个ref并加入

TS
useEffect(() => {
    setInterval(()=>{
      if(window.location.href.includes("/music")){
        const div1 = document.getElementById('aplayer');
        const div2 = document.getElementById('musicpage-aplayer');
        if(div1&&div2&&!(div1?.parentElement==div2)){
          playerRef.current=div1;
          div2.appendChild(div1)
        }
      }
      else{
        const div1 = document.getElementById('out-aplayer');
        if(div1&&playerRef.current&&(!(playerRef.current?.parentElement==div1))){
          div1.appendChild(playerRef.current);
        }
      }
    },1000);
  }, []);

就好了

一些收获

useState()useRef()的区别

之前尝试把HTML的元素装进state里发现不管怎样那个state就是undefined后来改成用ref就发现元素被装进去了。说明一般ref就用来存储HTML元素,state存其他的(数字、字符串之类)

window as any

后来觉得我尝试用context搞aplayer,Aria告诉我一个不太优雅但是很简单的方法,给window这个全局变量直接加属性,直接实现组件之间信息互通,不用一层一层套ContextProvider了。(解决了为什么Aria的前端里有一堆(window as any).xxx的困惑)