Home Web Front-end JS Tutorial React Update Notes Companion

React Update Notes Companion

Jan 12, 2025 pm 04:39 PM

React Update Notes Companion

Update notes for new major versions of React are always incredibly information dense, and the framework itself is so broad that I always find myself taking notes and comparing vs reference documentation to try to not just figure out what changed and how to use it, but also how the various major concepts the update notes talk about actually worked under the hood. While React is extremely well documented, the update notes aren’t always “enough” to understand the concepts - for example, in the React 19 update notes, I found useOptimistic’s example confusing and actually a little inaccurate to how the hook actually works.

I’ve decided to write the notes I took while going over the React 19 changes into a companion for anyone who’s been dreading combing through the notes and figuring out what they all mean - so let’s get started.

Actions & Form Handling/useActionState

The first major improvement has been huge improvements to form handling. React has gradually been moving to remove boilerplate and better integrate with native HTML forms, and its new useActionState is part of this push. It’s intended to help improve error handling (as it’s now built-in), it automatically tracks loading states so that you don’t have to manually code in pending states constantly, and improves support for progressive enhancement.

Now, I found the code example provided for useActionState to be pretty confusing, and in fact this code example is the entire reason I started writing this article - there are, in fact, two parts to useActionState, which they combined in the example to save space, but ended up greatly reducing clarity. useActionState returns a tuple that tracks when the async action in the form submission is complete, while a modified version of the action you pass it is directly passed to the form. useActionState itself takes two inputs - an async formAction (which receives both the previous state and the form data as arguments when called) and the initial state - which can be null, zero, or a variable.

If your form hasn’t yet been submitted, the previous state is the initialState. If the form has been previously submitted, it’s whatever was submitted - in a server function, you can actually display the server response before hydration even happens. useActionState lastly can accept a string with a unique page url that the form is intended to modify. In other words, it can also accept an optional permalink parameter, which is particularly useful for progressive enhancement - it tells the browser where to navigate if a user submits the form before JavaScript has loaded.

Lastly, the tuple that useActionState returns is an array consisting of the current state (during your initial render it’s your initialState value), the react-modified formAction you can pass to a form as an action or a button as a prop, and an isPending flag/stateful variable. I’m looking forward to seeing what other new developments the React team will come up with, since this one seems particularly useful.

React-DOM updates

actions

This react-dom addition will be familiar to anyone who has been using NextJS and form actions, and it seems the Reac team has decided form actions are ready for prime-time. For anyone who hasn’t used them in NextJS or another framework on top of react, they are basically a way to enhance React’s performance by using native form submission. Instead of onClick, you can pass native form submissions via the action prop - any function passed to action or formAction will have its submission handled automatically. React will also automatically reset any uncontrolled form fields. You also have manual options for resetting it via API. The React team has also integrated error handling with error boundaries. I won’t talk too much about it since I’m assuming most people remember them from NextJS, but I can write a followup if anyone has questions.

useFormStatus hook

This is a great addition to help you see what’s going on in your form without prop drilling or using context - if you’re asking why not prop drill, it has to do with keeping code maintainable and easy to modify. As for context, overusing context is going to cause performance issues since every component subscribed to a particular context will rerender whenever something in the context changes. So it declutters code, reduces the chance of errors, and stops you from gumming up your app’s performance.

The hook returns an object with four properties: pending - a boolean that says if there’s a pending submission, data - a formData object with the data submitted by the parent form (this is null if there is no active submission or parent form), method (get or post), and action - which is the action being passed through the action prop.

useOptimistic hook

The new simpler way to manage optimistic updates. If you’re not familiar with optimistic updates, it means updating the client-side display before the server-side updates happen. If you’ve ever liked something, seen the animation play and had it register on your screen as liked, then received a toast error saying “like failed”, this is due to optimistic rendering.

The useOptimistic hook accepts a stateful variable you want optimistically rendered and an update function, which must be a pure function - in other words, a deterministic function with no side effects. Basically, the update function retrieves the source of the update to state - so typically something like formData.get(‘name’). useOptimistic then returns two values: the optimistic state and an addOptimistic function.

I found the documentation for this a little weak, particularly around the usage flow - basically, you call useOptimistic and pass it the initial state that you want to display optimistic updates for and an update function. You receive two functions - the newly optimistic-enhanced stateful value (optimisticState) and a function to optimistically change state. When you have a new value submitted by the user, you call the second function, referred to as addOptimistic in the docs, and pass it the user-submitted value. In your component, you then pass it the optimistic-enhanced stateful value whenever you want to render the stateful var optimistically.

Overall, I really like this more standardized way of performing optimistic updates - I’ve previously had issues with caching in NextJS and making optimistic updates, so a standardized way of creating optimistic updates is great, and I’m sure this will bubble up to NextJS, if it hasn’t already.

The use API

This is a super dense API, and it’s a brand new way to access resources while react is rendering a page - the exact phrasing used is “reading resources in render”. So what specifically is it for? This new API can be used to access component information inside of conditionals or loops. If you aren’t familiar with why this is useful, it has to do with how React’s rendering process works. React/react-fiber relies on rendering everything in the same order each time, which is why you can’t generally access most hooks during the rendering process. To put it more clearly, state is actually tracked based on the order hooks are called in, so if hooks are called in an unpredictable order, you end up with rendering bugs. A great example is accessing a theme context depending on whether or not the user is logged in.

So why is this an important development? It means that you can load information/data only when it’s actually necessary, e.g. only if a user is actually logged in will you load css for a special theme. The data has to be serializable, so that means you can send a promise from the server component to a client component while it is in fact already in flight - this means there are fewer waterfall requests and they are automatically put in parallel. It's worth noting that when working in Server Components, you should actually prefer using async/await over use for data fetching - this is because async/await will resume rendering from exactly where it left off, while use will trigger a full re-render of the component after the data resolves. Of course, I also want to note that this change actually also means you have a new potential source of waterfall requests if you configure use incorrectly.

One really important thing to note is that you cannot use the “use” API in a try/catch block - this is because “use” automatically uses react suspense boundaries when called with a promise. A try/catch block prevents you from ever reaching the react level since any error would actually stop execution on the JS level before you ever reach React, breaking the functionality. Like other hooks, they have to be in the top level of scope of a particular component or function (again, due to render order).

So, what is the actual purpose of “use” is to help you access context to render things conditionally and only fetch data when it’s actually necessary. It’s yet another step towards making react a bit less arcane, simplifying conditional data fetching, improving dev experience, and improving performance all in one fell swoop. It requires more experienced React devs to relearn how to do things like theming, but I think it makes the framework a lot more accessible to new users, which is always great.

New React Dom Static APIs

These two new static APIs, prerender and prerenderToNodeStream are both improvements to renderToString, which is used for Server Side Rendering (SSR). These new improvements are for doing Static Site Generation (SSG) using renderToString. Unlike traditional streaming SSR which can send content chunks as they become available, these new APIs specifically wait for ALL data to load before generating the final HTML. They're designed to work seamlessly with modern streaming environments like Node.js Streams and Web Streams, but they intentionally don't support streaming partial content - instead, they ensure you get complete, fully-loaded pages at build time. They differ from traditional streaming SSR methods, which send pre-rendered sites as data becomes available.

We already had SSG-capable frameworks built on top of React, like NextJS, but this is intended to be React’s native functionality for SSG. The frameworks that had SSG used renderToString, then built their own complex data fetching coordinations around it. This was extremely difficult for users to create themselves, and these frameworks used extremely complex pipelines to do so. What these new methods do is essentially allow for data to load during static HTML generation, If you aren’t familiar with SSG, it’s essentially rendering everything at build time, and is undoubtedly the fastest method of rendering pages, as it doesn’t have to render pages on user request, so it’s great to have this kind of functionality for people who don’t want to use something like Next, which either requires deployment on Vercel or an extremely complex deployment process.

Server Components

The concept of React Server Components won’t be new to anyone who’s used a recent version of NextJS, but for anyone who hasn’t, server components are a new paradigm around data fetching. Frankly, the concept of Server Components (and Server Actions) deserve an entire article themselves, but to sum up the concept briefly, server components are always rendered on the server before being sent to the client, even after javascript is loaded. That means subsequent renders are done server-side.

The main advantage of these components is security and data fetching: if you request data inside a server component, the request information never shows up client-side, only the response, making it much more secure. APIs, endpoints, etc. simply are not accessible client-side. It also reduces bundle size since the javascript for said actions is never sent to the client. It additionally allows you to execute memory or computationally intensive operations on the server to reduce the burden of rendering on less powerful machines. They also reduce client-side waterfalls since sequential data fetching can be performed on machines closer to your databases, but of course it also opens up the possibility of brand new server-side waterfalls since your devs lose access to easy request information from test browser developer tools and have to use something like an OpenTelemetry collector and viewer to examine them. Lastly, server components are also great for progressive enhancement.

Server components also come with a list of limitations: you can’t use local browser APIs (local storage, window, etc), react hooks will work differently, you can’t rely on or use state, and you can’t use event handlers, so user interactivity for the components is decidedly slim. Basically, think of this paradigm as data fetching in server components, interactivity on client components.

The most important caveat for anyone new to server components is that you cannot import them into a client component - if you do, this will error out (assuming you’ve added some data fetching) because it causes the compiler to treat said server component as a client component. If you want to pass a server component to a client component, you need to pass it via the {children} prop.

Server Actions

These are another complex topic with a lot of implications for how you build your products and features, and these have also been present in NextJS for a year or so. Server actions are declared by typing ‘use server’ at the top of a file, and pass a direct reference to said server function which can then be called from inside of a client component.

On some level, these are conceptually similar to Remote Procedure Calls (RPC) - they both let you call server-side functions from the client, both abstract the complexity of client-server interactions, and both handle serialization and deserialization, but there are a few key differences to be aware of. The main benefit of server actions is that they work with React’s progressive enhancement,, help enforce type-safety across client/server boundaries, have built-in performance optimizations (related to progressive enhancement), and have a more seamless integration with the React ecosystem in that they provide built-in pending states and are automatically integrated with native form submissions.

When you’re talking about modern RPC, something like gRPC that already has type safety and some performance optimizations, the main advantage of server actions generally boils down to said built-in form handling and progressive enhancement, but importantly it also works with react suspense and error boundaries. Most importantly, deployment is a lot simpler since you don’t necessarily need to set up separate server for gRPC, so these are absolutely more ideal for smaller projects, though when it comes to larger projects I can see gRPC being a lot more desirable since it gives you more flexibility in terms of backend language, etc.

Context as a Provider

This is essentially a simplification of the syntax, helping React in general have a much cleaner, declarative syntax. To be honest I don’t have much to say about this aside from “I like it”.

Ref as a Prop & Cleanup Functions for Refs

Previously, to clean up refs, you had to perform a null check inside of your component, and the ref would be cleaned up at a somewhat indeterminate time. React would call your ref callback with null when the component unmounted, requiring you to handle both the attachment and detachment cases explicitly. The advantage of the new ref syntax is deterministic cleanup - which means it’s now a lot easier to work with external resources and third party libraries because you will know exactly when ref cleanup happens (on unmount). With the new approach, you can return a cleanup function directly. The TypeScript integration requires explicit return statements to avoid ambiguity about cleanup functions.

I really like the way this was implemented since it’s the same pattern from useEffect - maintaining consistency across the framework is great. I think this new ref cleanup is specifically going to be really useful for WebGL contexts and other heavy resources, but also for handling DOM event listeners added using native JS methods. This is because previously, react would remove the ref to the dom element on cleanup…But then if you’ve done that, it becomes much more complex to remove event listeners since you’ve lost the reference to the component they’re attached to. As a result, you had to store your refs outside of the element, adding a layer of complexity. Now you can just remove event listeners inside your component’s return function because you retain access to the ref inside said return function. This also means we no longer need to worry about the null case in most situations, as React won't call the ref with null anymore when using cleanup functions. The cleanup function itself replaces that functionality, making our code cleaner and more predictable.

useDeferredValue

The purpose of the useDeferredValue hook is to manage computationally expensive operations while maintaining a responsive user interface. It accomplishes this by allowing components to show a previous "stale" value while calculating or fetching new data in the background. A common use case is search functionality that displays results as users type - without deferring, each keystroke could trigger an expensive search operation that makes the input feel sluggish. Using useDeferredValue, the interface can remain responsive by showing previous search results while computing new ones.

This new addition is an important improvement to this hook's initial loading behavior. Previously, the first render would immediately use whatever value was passed to useDeferredValue, potentially triggering an expensive computation right at the start. The new version allows you to provide a lightweight initial value (such as an empty string) that displays immediately, while processing the more expensive value in the background. This means you can show users immediate feedback with a safe default value, then update it with real data once the expensive computation completes. Essentially, this makes useDeferredValue even better for performance improvement.

Document Metadata Additions

These new changes are for adding various metadata tags inside of actual components. There are three options they go over: , , and <meta>. It’s important to note that <title> has no deduplication - you’re only intended to use it once per repo. The other two, <link> and <meta>, have some pretty complex interactions regarding deduplication that, after learning, I think aren’t going to be particularly relevant for 90% of users. </p> <p>The main benefit from these changes is that they allow components to truly be self-contained: they can now manage their own metadata along with their styles and scripts. You don’t need to figure out how to lift metadata to the top level or make use of a library to do it anymore, which makes SEO far easier to do. Different pages in an SPA can have different metadata more easily without risking metadata becoming out of sync with the content displayed on the page, which was previously a risk when having different metadata for different pages.</p> <p><strong>Stylesheet Support</strong></p> <p>People may have been using tailwind so long that they’ve forgotten, but running non-encapsulated CSS can create issues due to how stylesheets are loaded - namely, load order precedence rules. First, you can end up with flashes of unstyled content - any time the HTML loads and renders before the CSS is finished downloading, it displays as a completely white page, typically in a single column with massive font sizes and native image sizes, which often makes it unreadable.</p> <p>Additionally, CSS load order rules can create other problems: for example, if you have rules with the same specificity but expect them to load in a certain order. This is relevant, for example, when you have different options for themes (e.g. dark mode). If the dark mode CSS is intended to load last, but your CSS file for dark mode loads first, you can end up with dark mode being light, or some parts of the app where the rules are adhered to and other parts where they aren’t adhered to. </p> <p>There were a lot of solutions for avoiding this, like CSS in JS, loading all CSS in the <head> tag, build time bundling CSS together, etc. However, these new CSS changes are intended to help manage these issues by declaratively setting precedence - it also ensures any stylesheets placed in a component are loaded before the component itself renders. It’s also got built in deduping, so you don’t end up loading the same stylesheet multiple times when you reuse components with stylesheet links included. </p> <p>The way you access this new functionality (waiting for the css to load before rendering a component, hoisting CSS automatically to the head, etc.) is pretty simple too - you just need to include a precedence in a particular <link> component. Overall, I’m a typescript enjoyer, so it doesn’t exactly address any particular issues for me, but I’m sure this will be extremely useful large legacy projects. </p> <p><strong>Async Script Support</strong></p> <p>This addresses an edge case, as opposed to creating a new core functionality for people to worry about - manually adding/directly managing scripts with a <script> tag is pretty rare in modern React in my experience. Most devs are using bundlers like webpack or vite, package managers, import statements, and if scripts need to be dynamically loaded they use something like useEffect. However, this is relevant for SSR and better UX to avoid the aforementioned issues with load order of the contents in the <head>. </p> <p>Since scripts can be loaded asynchronously, it means there’s a significantly lower chance of react apps loading without proper styles. The change is also relevant for devs managing legacy systems that require direct script tags or devs responsible for managing third-party scripts that can’t be bundled (e.g. analytics, widgets, etc.), or preventing a particularly heavy script (e.g. a video player) loading before it’s necessary to improve performance, but since I don’t have experience with those, I can’t really comment much more than that. </p> <p><strong>Support for Preloading Resources</strong></p> <p>The new APIs for managing resource preloading are quite interesting, particularly for larger enterprises that have to ensure seamless loading experiences for global audiences with widely varying network conditions, for particularly content-heavy apps that rely on heavy third party resources from different sources, and for any app where perceived performance is important to user retention (which, to be honest, is nearly everything) </p> <p>However, most frameworks that sit on top of react (e.g. Next, Remix, etc.) tended to already manage this - I’m not quite sure how these new APIs will interact with said frameworks, but it seems like it’ll be a new source of conflicts and something important to keep in mind when using these frameworks and attempting to optimize performance using these new APIs. </p> <p>While preload is definitely the API with the widest use case (loading stylesheets etc.), thanks to the above issue the one I think has the most relevance is preinit - it’s a hard load that starts immediately and is intended for eagerly loading scripts. The most obvious use I can think of is something like immediately loading stripe on shopping cart review - this should speed up the checkout process significantly, which is a step of e-commerce where you absolutely don’t want to lose customers due to performance issues. </p> <p><strong>Third Party Script Compatibility</strong></p> <p>This is a pretty welcome change given how increasingly common browser addons are - some examples I can think of that modify DOM structure that probably benefit from this change are ad blockers, price comparison tools, grammar/AI assistant addons, and translation extensions. Not much else to say about this without actually reading how hydration works now, though it seems the main change is that the compiler skips over unexpected tags. </p> <p><strong>Better Error Reporting</strong></p> <p>I found this section to be pretty self-explanatory. Error handling changes are always welcome - the error spam that previously existed always made it a bit harder to track down specific errors. This is particularly relevant if you use some less well maintained third party solutions that tend to fire off a ton of errors.<br> Support for Custom Elements</p> <p>This section was particularly interesting to me since I hadn’t heard of Custom Elements before. The rundown is that Custom Elements are a new web standard to let devs create their own HTML elements. Thanks to following said web standards, they’re intended to function on any page and be framework agnostic - for example you could write a component you commonly use in all your personal projects, which you tend to do in svelte, then use it for smaller contract work you do for startups or short term contracts in vue, etc. </p> <p>React used to treat unrecognized props as attributes instead of actual properties - the new update has added a system that allows props to be properly used to create custom elements. It seems with this change, there is now full support for using Custom Elements in react. On a side note, in addition to the props issue, there used to also be incompatibilities (now resolved) with react’s synthetic events system - Custom Elements couldn’t cleanly integrate with the system, so there were some cases where you actually had to manually add event listeners with ref, among other workarounds. </p> <p>The above is the detailed content of React Update Notes Companion. For more information, please follow other related articles on the PHP Chinese website!</p> </div> </div> <div class="wzconShengming_sp"> <div class="bzsmdiv_sp">Statement of this Website</div> <div>The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn</div> </div> </div> <ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5902227090019525" data-ad-slot="2507867629"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> <div class="AI_ToolDetails_main4sR"> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5902227090019525" data-ad-slot="3653428331" data-ad-format="auto" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> <!-- <div class="phpgenera_Details_mainR4"> <div class="phpmain1_4R_readrank"> <div class="phpmain1_4R_readrank_top"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/hotarticle2.png" alt="" /> <h2>Hot Article</h2> </div> <div class="phpgenera_Details_mainR4_bottom"> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796793874.html" title="How to fix KB5055523 fails to install in Windows 11?" class="phpgenera_Details_mainR4_bottom_title">How to fix KB5055523 fails to install in Windows 11?</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>3 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796793871.html" title="How to fix KB5055518 fails to install in Windows 10?" class="phpgenera_Details_mainR4_bottom_title">How to fix KB5055518 fails to install in Windows 10?</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>3 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796791957.html" title="Roblox: Dead Rails - How To Tame Wolves" class="phpgenera_Details_mainR4_bottom_title">Roblox: Dead Rails - How To Tame Wolves</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>4 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796792155.html" title="Strength Levels for Every Enemy & Monster in R.E.P.O." class="phpgenera_Details_mainR4_bottom_title">Strength Levels for Every Enemy & Monster in R.E.P.O.</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>4 weeks ago</span> <span>By 尊渡假赌尊渡假赌尊渡假赌</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796797907.html" title="Roblox: Grow A Garden - Complete Mutation Guide" class="phpgenera_Details_mainR4_bottom_title">Roblox: Grow A Garden - Complete Mutation Guide</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>2 weeks ago</span> <span>By DDD</span> </div> </div> </div> <div class="phpgenera_Details_mainR3_more"> <a href="https://www.php.cn/article.html">Show More</a> </div> </div> </div> --> <div class="phpgenera_Details_mainR3"> <div class="phpmain1_4R_readrank"> <div class="phpmain1_4R_readrank_top"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/hottools2.png" alt="" /> <h2>Hot AI Tools</h2> </div> <div class="phpgenera_Details_mainR3_bottom"> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/ai/undresserai-undress" title="Undresser.AI Undress" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/ai_manual/001/246/273/173411540686492.jpg?x-oss-process=image/resize,m_fill,h_50,w_50" src="/static/imghw/default1.png" alt="Undresser.AI Undress" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/ai/undresserai-undress" title="Undresser.AI Undress" class="phpmain_tab2_mids_title"> <h3>Undresser.AI Undress</h3> </a> <p>AI-powered app for creating realistic nude photos</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/ai/ai-clothes-remover" title="AI Clothes Remover" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/ai_manual/001/246/273/173411552797167.jpg?x-oss-process=image/resize,m_fill,h_50,w_50" src="/static/imghw/default1.png" alt="AI Clothes Remover" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/ai/ai-clothes-remover" title="AI Clothes Remover" class="phpmain_tab2_mids_title"> <h3>AI Clothes Remover</h3> </a> <p>Online AI tool for removing clothes from photos.</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/ai/undress-ai-tool" title="Undress AI Tool" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/ai_manual/001/246/273/173410641626608.jpg?x-oss-process=image/resize,m_fill,h_50,w_50" src="/static/imghw/default1.png" alt="Undress AI Tool" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/ai/undress-ai-tool" title="Undress AI Tool" class="phpmain_tab2_mids_title"> <h3>Undress AI Tool</h3> </a> <p>Undress images for free</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/ai/clothoffio" title="Clothoff.io" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/ai_manual/001/246/273/173411529149311.jpg?x-oss-process=image/resize,m_fill,h_50,w_50" src="/static/imghw/default1.png" alt="Clothoff.io" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/ai/clothoffio" title="Clothoff.io" class="phpmain_tab2_mids_title"> <h3>Clothoff.io</h3> </a> <p>AI clothes remover</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/ai/video-swap" title="Video Face Swap" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/ai_manual/001/246/273/173414504068133.jpg?x-oss-process=image/resize,m_fill,h_50,w_50" src="/static/imghw/default1.png" alt="Video Face Swap" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/ai/video-swap" title="Video Face Swap" class="phpmain_tab2_mids_title"> <h3>Video Face Swap</h3> </a> <p>Swap faces in any video effortlessly with our completely free AI face swap tool!</p> </div> </div> </div> <div class="phpgenera_Details_mainR3_more"> <a href="https://www.php.cn/ai">Show More</a> </div> </div> </div> <script src="https://sw.php.cn/hezuo/cac1399ab368127f9b113b14eb3316d0.js" type="text/javascript"></script> <div class="phpgenera_Details_mainR4"> <div class="phpmain1_4R_readrank"> <div class="phpmain1_4R_readrank_top"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/hotarticle2.png" alt="" /> <h2>Hot Article</h2> </div> <div class="phpgenera_Details_mainR4_bottom"> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796793874.html" title="How to fix KB5055523 fails to install in Windows 11?" class="phpgenera_Details_mainR4_bottom_title">How to fix KB5055523 fails to install in Windows 11?</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>3 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796793871.html" title="How to fix KB5055518 fails to install in Windows 10?" class="phpgenera_Details_mainR4_bottom_title">How to fix KB5055518 fails to install in Windows 10?</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>3 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796791957.html" title="Roblox: Dead Rails - How To Tame Wolves" class="phpgenera_Details_mainR4_bottom_title">Roblox: Dead Rails - How To Tame Wolves</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>4 weeks ago</span> <span>By DDD</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796792155.html" title="Strength Levels for Every Enemy & Monster in R.E.P.O." class="phpgenera_Details_mainR4_bottom_title">Strength Levels for Every Enemy & Monster in R.E.P.O.</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>4 weeks ago</span> <span>By 尊渡假赌尊渡假赌尊渡假赌</span> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/1796797907.html" title="Roblox: Grow A Garden - Complete Mutation Guide" class="phpgenera_Details_mainR4_bottom_title">Roblox: Grow A Garden - Complete Mutation Guide</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <span>2 weeks ago</span> <span>By DDD</span> </div> </div> </div> <div class="phpgenera_Details_mainR3_more"> <a href="https://www.php.cn/article.html">Show More</a> </div> </div> </div> <div class="phpgenera_Details_mainR3"> <div class="phpmain1_4R_readrank"> <div class="phpmain1_4R_readrank_top"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/hottools2.png" alt="" /> <h2>Hot Tools</h2> </div> <div class="phpgenera_Details_mainR3_bottom"> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/toolset/development-tools/92" title="Notepad++7.3.1" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/manual/000/000/001/58ab96f0f39f7357.jpg?x-oss-process=image/resize,m_fill,h_50,w_72" src="/static/imghw/default1.png" alt="Notepad++7.3.1" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/toolset/development-tools/92" title="Notepad++7.3.1" class="phpmain_tab2_mids_title"> <h3>Notepad++7.3.1</h3> </a> <p>Easy-to-use and free code editor</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/toolset/development-tools/93" title="SublimeText3 Chinese version" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/manual/000/000/001/58ab97a3baad9677.jpg?x-oss-process=image/resize,m_fill,h_50,w_72" src="/static/imghw/default1.png" alt="SublimeText3 Chinese version" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/toolset/development-tools/93" title="SublimeText3 Chinese version" class="phpmain_tab2_mids_title"> <h3>SublimeText3 Chinese version</h3> </a> <p>Chinese version, very easy to use</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/toolset/development-tools/121" title="Zend Studio 13.0.1" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/manual/000/000/001/58ab97ecd1ab2670.jpg?x-oss-process=image/resize,m_fill,h_50,w_72" src="/static/imghw/default1.png" alt="Zend Studio 13.0.1" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/toolset/development-tools/121" title="Zend Studio 13.0.1" class="phpmain_tab2_mids_title"> <h3>Zend Studio 13.0.1</h3> </a> <p>Powerful PHP integrated development environment</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/toolset/development-tools/469" title="Dreamweaver CS6" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/manual/000/000/001/58d0e0fc74683535.jpg?x-oss-process=image/resize,m_fill,h_50,w_72" src="/static/imghw/default1.png" alt="Dreamweaver CS6" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/toolset/development-tools/469" title="Dreamweaver CS6" class="phpmain_tab2_mids_title"> <h3>Dreamweaver CS6</h3> </a> <p>Visual web development tools</p> </div> </div> <div class="phpmain_tab2_mids_top"> <a href="https://www.php.cn/toolset/development-tools/500" title="SublimeText3 Mac version" class="phpmain_tab2_mids_top_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" class="lazy" data-src="https://img.php.cn/upload/manual/000/000/001/58d34035e2757995.png?x-oss-process=image/resize,m_fill,h_50,w_72" src="/static/imghw/default1.png" alt="SublimeText3 Mac version" /> </a> <div class="phpmain_tab2_mids_info"> <a href="https://www.php.cn/toolset/development-tools/500" title="SublimeText3 Mac version" class="phpmain_tab2_mids_title"> <h3>SublimeText3 Mac version</h3> </a> <p>God-level code editing software (SublimeText3)</p> </div> </div> </div> <div class="phpgenera_Details_mainR3_more"> <a href="https://www.php.cn/ai">Show More</a> </div> </div> </div> <div class="phpgenera_Details_mainR4"> <div class="phpmain1_4R_readrank"> <div class="phpmain1_4R_readrank_top"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/hotarticle2.png" alt="" /> <h2>Hot Topics</h2> </div> <div class="phpgenera_Details_mainR4_bottom"> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/java-tutorial" title="Java Tutorial" class="phpgenera_Details_mainR4_bottom_title">Java Tutorial</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/eyess.png" alt="" /> <span>1657</span> </div> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/tiezi.png" alt="" /> <span>14</span> </div> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/cakephp-tutor" title="CakePHP Tutorial" class="phpgenera_Details_mainR4_bottom_title">CakePHP Tutorial</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/eyess.png" alt="" /> <span>1415</span> </div> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/tiezi.png" alt="" /> <span>52</span> </div> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/laravel-tutori" title="Laravel Tutorial" class="phpgenera_Details_mainR4_bottom_title">Laravel Tutorial</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/eyess.png" alt="" /> <span>1309</span> </div> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/tiezi.png" alt="" /> <span>25</span> </div> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/php-tutorial" title="PHP Tutorial" class="phpgenera_Details_mainR4_bottom_title">PHP Tutorial</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/eyess.png" alt="" /> <span>1257</span> </div> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/tiezi.png" alt="" /> <span>29</span> </div> </div> </div> <div class="phpgenera_Details_mainR4_bottoms"> <a href="https://www.php.cn/faq/c-tutorial" title="C# Tutorial" class="phpgenera_Details_mainR4_bottom_title">C# Tutorial</a> <div class="phpgenera_Details_mainR4_bottoms_info"> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/eyess.png" alt="" /> <span>1229</span> </div> <div class="phpgenera_Details_mainR4_bottoms_infos"> <img src="/static/imghw/tiezi.png" alt="" /> <span>24</span> </div> </div> </div> </div> <div class="phpgenera_Details_mainR3_more"> <a href="https://www.php.cn/faq/zt">Show More</a> </div> </div> </div> </div> </div> <div class="Article_Details_main2"> <div class="phpgenera_Details_mainL4"> <div class="phpmain1_2_top"> <a href="javascript:void(0);" class="phpmain1_2_top_title">Related knowledge<img src="/static/imghw/index2_title2.png" alt="" /></a> </div> <div class="phpgenera_Details_mainL4_info"> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796793115.html" title="Demystifying JavaScript: What It Does and Why It Matters" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174412846042688.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="Demystifying JavaScript: What It Does and Why It Matters" /> </a> <a href="https://www.php.cn/faq/1796793115.html" title="Demystifying JavaScript: What It Does and Why It Matters" class="phphistorical_Version2_mids_title">Demystifying JavaScript: What It Does and Why It Matters</a> <span class="Articlelist_txts_time">Apr 09, 2025 am 12:07 AM</span> <p class="Articlelist_txts_p">JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796793650.html" title="The Evolution of JavaScript: Current Trends and Future Prospects" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174424878172869.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="The Evolution of JavaScript: Current Trends and Future Prospects" /> </a> <a href="https://www.php.cn/faq/1796793650.html" title="The Evolution of JavaScript: Current Trends and Future Prospects" class="phphistorical_Version2_mids_title">The Evolution of JavaScript: Current Trends and Future Prospects</a> <span class="Articlelist_txts_time">Apr 10, 2025 am 09:33 AM</span> <p class="Articlelist_txts_p">The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796795187.html" title="JavaScript Engines: Comparing Implementations" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174447395115481.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="JavaScript Engines: Comparing Implementations" /> </a> <a href="https://www.php.cn/faq/1796795187.html" title="JavaScript Engines: Comparing Implementations" class="phphistorical_Version2_mids_title">JavaScript Engines: Comparing Implementations</a> <span class="Articlelist_txts_time">Apr 13, 2025 am 12:05 AM</span> <p class="Articlelist_txts_p">Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796794156.html" title="JavaScript: Exploring the Versatility of a Web Language" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174430086367978.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="JavaScript: Exploring the Versatility of a Web Language" /> </a> <a href="https://www.php.cn/faq/1796794156.html" title="JavaScript: Exploring the Versatility of a Web Language" class="phphistorical_Version2_mids_title">JavaScript: Exploring the Versatility of a Web Language</a> <span class="Articlelist_txts_time">Apr 11, 2025 am 12:01 AM</span> <p class="Articlelist_txts_p">JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796796853.html" title="Python vs. JavaScript: The Learning Curve and Ease of Use" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174473354083140.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="Python vs. JavaScript: The Learning Curve and Ease of Use" /> </a> <a href="https://www.php.cn/faq/1796796853.html" title="Python vs. JavaScript: The Learning Curve and Ease of Use" class="phphistorical_Version2_mids_title">Python vs. JavaScript: The Learning Curve and Ease of Use</a> <span class="Articlelist_txts_time">Apr 16, 2025 am 12:12 AM</span> <p class="Articlelist_txts_p">Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796794257.html" title="How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/242/473/174433092927917.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)" /> </a> <a href="https://www.php.cn/faq/1796794257.html" title="How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)" class="phphistorical_Version2_mids_title">How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)</a> <span class="Articlelist_txts_time">Apr 11, 2025 am 08:22 AM</span> <p class="Articlelist_txts_p">This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796795636.html" title="From C/C to JavaScript: How It All Works" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174456030117549.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="From C/C to JavaScript: How It All Works" /> </a> <a href="https://www.php.cn/faq/1796795636.html" title="From C/C to JavaScript: How It All Works" class="phphistorical_Version2_mids_title">From C/C to JavaScript: How It All Works</a> <span class="Articlelist_txts_time">Apr 14, 2025 am 12:05 AM</span> <p class="Articlelist_txts_p">The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.</p> </div> <div class="phphistorical_Version2_mids"> <a href="https://www.php.cn/faq/1796790437.html" title="How do I install JavaScript?" class="phphistorical_Version2_mids_img"> <img onerror="this.onerror=''; this.src='/static/imghw/default1.png'" src="/static/imghw/default1.png" class="lazy" data-src="https://img.php.cn/upload/article/001/253/068/174378339020620.jpg?x-oss-process=image/resize,m_fill,h_207,w_330" alt="How do I install JavaScript?" /> </a> <a href="https://www.php.cn/faq/1796790437.html" title="How do I install JavaScript?" class="phphistorical_Version2_mids_title">How do I install JavaScript?</a> <span class="Articlelist_txts_time">Apr 05, 2025 am 12:16 AM</span> <p class="Articlelist_txts_p">JavaScript does not require installation because it is already built into modern browsers. You just need a text editor and a browser to get started. 1) In the browser environment, run it by embedding the HTML file through tags. 2) In the Node.js environment, after downloading and installing Node.js, run the JavaScript file through the command line.</p> </div> </div> <a href="https://www.php.cn/web-designer.html" class="phpgenera_Details_mainL4_botton"> <span>See all articles</span> <img src="/static/imghw/down_right.png" alt="" /> </a> </div> </div> </div> </main> <footer> <div class="footer"> <div class="footertop"> <img src="/static/imghw/logo.png" alt=""> <p>Public welfare online PHP training,Help PHP learners grow quickly!</p> </div> <div class="footermid"> <a href="https://www.php.cn/about/us.html">About us</a> <a href="https://www.php.cn/about/disclaimer.html">Disclaimer</a> <a href="https://www.php.cn/update/article_0_1.html">Sitemap</a> </div> <div class="footerbottom"> <p> © php.cn All rights reserved </p> </div> </div> </footer> <input type="hidden" id="verifycode" value="/captcha.html"> <script>layui.use(['element', 'carousel'], function () {var element = layui.element;$ = layui.jquery;var carousel = layui.carousel;carousel.render({elem: '#test1', width: '100%', height: '330px', arrow: 'always'});$.getScript('/static/js/jquery.lazyload.min.js', function () {$("img").lazyload({placeholder: "/static/images/load.jpg", effect: "fadeIn", threshold: 200, skip_invisible: false});});});</script> <script src="/static/js/common_new.js"></script> <script type="text/javascript" src="/static/js/jquery.cookie.js?1746436854"></script> <script src="https://vdse.bdstatic.com//search-video.v1.min.js"></script> <link rel='stylesheet' id='_main-css' href='/static/css/viewer.min.css?2' type='text/css' media='all' /> <script type='text/javascript' src='/static/js/viewer.min.js?1'></script> <script type='text/javascript' src='/static/js/jquery-viewer.min.js'></script> <script type="text/javascript" src="/static/js/global.min.js?5.5.53"></script> <script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function () { var u = "https://tongji.php.cn/"; _paq.push(['setTrackerUrl', u + 'matomo.php']); _paq.push(['setSiteId', '9']); var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0]; g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s); })(); </script> <script> // top layui.use(function () { var util = layui.util; util.fixbar({ on: { mouseenter: function (type) { layer.tips(type, this, { tips: 4, fixed: true, }); }, mouseleave: function (type) { layer.closeAll("tips"); }, }, }); }); document.addEventListener("DOMContentLoaded", (event) => { // 定义一个函数来处理滚动链接的点击事件 function setupScrollLink(scrollLinkId, targetElementId) { const scrollLink = document.getElementById(scrollLinkId); const targetElement = document.getElementById(targetElementId); if (scrollLink && targetElement) { scrollLink.addEventListener("click", (e) => { e.preventDefault(); // 阻止默认链接行为 targetElement.scrollIntoView({ behavior: "smooth" }); // 平滑滚动到目标元素 }); } else { console.warn( `Either scroll link with ID '${scrollLinkId}' or target element with ID '${targetElementId}' not found.` ); } } // 使用该函数设置多个滚动链接 setupScrollLink("Article_Details_main1L2s_1", "article_main_title1"); setupScrollLink("Article_Details_main1L2s_2", "article_main_title2"); setupScrollLink("Article_Details_main1L2s_3", "article_main_title3"); setupScrollLink("Article_Details_main1L2s_4", "article_main_title4"); setupScrollLink("Article_Details_main1L2s_5", "article_main_title5"); setupScrollLink("Article_Details_main1L2s_6", "article_main_title6"); // 可以继续添加更多的滚动链接设置 }); window.addEventListener("scroll", function () { var fixedElement = document.getElementById("Article_Details_main1Lmain"); var scrollTop = window.scrollY || document.documentElement.scrollTop; // 兼容不同浏览器 var clientHeight = window.innerHeight || document.documentElement.clientHeight; // 视口高度 var scrollHeight = document.documentElement.scrollHeight; // 页面总高度 // 计算距离底部的距离 var distanceToBottom = scrollHeight - scrollTop - clientHeight; // 当距离底部小于或等于300px时,取消固定定位 if (distanceToBottom <= 980) { fixedElement.classList.remove("Article_Details_main1Lmain"); fixedElement.classList.add("Article_Details_main1Lmain_relative"); } else { // 否则,保持固定定位 fixedElement.classList.remove("Article_Details_main1Lmain_relative"); fixedElement.classList.add("Article_Details_main1Lmain"); } }); </script> <script> document.addEventListener('DOMContentLoaded', function() { const mainNav = document.querySelector('.Article_Details_main1Lmain'); const header = document.querySelector('header'); if (mainNav) { window.addEventListener('scroll', function() { const scrollPosition = window.scrollY; if (scrollPosition > 84) { mainNav.classList.add('fixed'); } else { mainNav.classList.remove('fixed'); } }); } }); </script> </body> </html>