在Gatsby JS中使用外部脚本(JavaScript)
我正在尝试在我的盖茨比应用程序上加载JavaScript代码。在根文件夹的静态文件夹中,我创建了一个名为在Gatsby JS中使用外部脚本(JavaScript),javascript,reactjs,react-hooks,gatsby,Javascript,Reactjs,React Hooks,Gatsby,我正在尝试在我的盖茨比应用程序上加载JavaScript代码。在根文件夹的静态文件夹中,我创建了一个名为script.js的代码。下面是其中的片段: window.addEventListener("scroll", function(e) { const navBar = document.querySelector(".navbar"); if (this.scrollY > 10) { navBar.classList.add(
script.js
的代码。下面是其中的片段:
window.addEventListener("scroll", function(e) {
const navBar = document.querySelector(".navbar");
if (this.scrollY > 10) {
navBar.classList.add("active");
} else {
navBar.classList.remove("active");
}
})
然后在我的布局
组件上,我尝试使用头盔来包含以下内容:
import React, { useEffect } from "react"
import { withPrefix, Link } from "gatsby"
import Helmet from "react-helmet"
import Navbar from '../components/Navbar'
import Footer from '../components/Footer'
const Layout = ({ children }) => {
<Helmet>
<script src={withPrefix('script.js')} type="text/javascript" />
</Helmet>
let AOS;
useEffect(() => {
const AOS = require("aos");
AOS.init({
once: true,
});
}, []);
useEffect(() => {
if (AOS) {
AOS.refresh();
}
});
return (
<>
<Navbar />
{ children}
<Footer />
</>
)
}
export default Layout
我不确定是否应该将脚本放在匿名函数中以进行此调用,但如何修复此问题
更新:
正如@Ferran所说,我需要在我的应用程序中使用脚本代码作为钩子。不确定我是否做对了,但以下是我做的步骤
在我的Navbar.js
中,我创建了一个useState钩子,它将处理调整窗口大小的功能:
import React, { useEffect, useState } from "react"
import { Link } from 'gatsby'
import useWindowSize from '../../static/script.js'
const Navbar = () => {
const [navBarClass, setNavBarClass] = useState("")
const { height } = useWindowSize()
useEffect(()=>{
if(height > 10)setNavBarClass("active")
}, [height])
return (
<header className="header sticky-header">
<nav className={`navbar navbar-expand-lg fixed-top py-3 ${navBarClass}`}>
<div class="container container-wide">
<Link to="/"><img src={MainLogo} alt="" /></Link>
<button type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" className="navbar-toggler navbar-toggler-right"><i className="fa fa-bars"></i></button>
<div id="navbarSupportedContent" className="collapse navbar-collapse">
<ul className="navbar-nav ms-auto">
<li className="nav-item active"><a href="#" class="nav-link text-uppercase font-weight-bold">Home <span class="sr-only">(current)</span></a></li>
<li className="nav-item"><a href="#" class="nav-link text-uppercase font-weight-bold">About</a></li>
<li className="nav-item"><a href="#" class="nav-link text-uppercase font-weight-bold">Gallery</a></li>
<li className="nav-item"><a href="#" class="nav-link text-uppercase font-weight-bold">Portfolio</a></li>
<li className="nav-item"><a href="#" class="nav-link text-uppercase font-weight-bold">Contact</a></li>
</ul>
</div>
</div>
</nav>
</header>
)
}
export default Navbar
然后回到Navbar.js
我将其作为组件导入:
import useWindowSize from '../../static/script.js'
我这样做对吗?
是一个组件,因此必须将其放在return
语句中:
return (
<>
<Helmet>
<script src={withPrefix('script.js')} type="text/javascript" />
</Helmet>
<Navbar />
{ children}
<Footer />
</>
)
useCrollPosition
是一个自定义挂钩,看起来可能像:
import { useLayoutEffect, useRef } from 'react';
const isBrowser = typeof window !== `undefined`;
const getScrollPosition = ({ element, useWindow }) => {
if (!isBrowser) return { x: 0, y: 0 };
const target = element ? element.current : document.body,
position = target.getBoundingClientRect();
return useWindow
? { x: window.scrollX, y: window.scrollY }
: { x: position.left, y: position.top };
};
export const useScrollPosition = (effect, deps, element, useWindow, wait) => {
const position = useRef(getScrollPosition({ useWindow }));
let throttleTimeout = null;
const callBack = () => {
const currentPosition = getScrollPosition({ element, useWindow });
effect({ previousPosition: position.current, currentPosition: currentPosition });
position.current = currentPosition;
throttleTimeout = null;
};
useLayoutEffect(() => {
const handleScroll = () => {
if (wait && !throttleTimeout) throttleTimeout = setTimeout(callBack, wait);
else callBack();
};
window.addEventListener(`scroll`, handleScroll);
return () => window.removeEventListener(`scroll`, handleScroll);
}, deps);
};
基本上,您是在React的生态系统中包装计算窗口内容的逻辑,使用状态,这不会破坏您的补水
这样,您就创建了一个保存nav
类名的状态,初始设置为空(const[navBarClass,setNavBarClass]=useState(“”
),以及一个保存当前滚动位置的状态(const[scroll,setScroll]=useState(0)
),初始设置为0
另一方面,每当窗口的滚动
更改时(用户正在滚动),就会触发useffect
钩子,这是由deps
数组([scroll]
)控制的,如果滚动条大于或不大于10,则保持设置/删除新类名的逻辑
由于类名状态已更改,组件将再次重新水化,实时显示/隐藏类名。最后,计算窗口参数的逻辑由自定义挂钩控制,其内部逻辑不属于您的组件
附言:例如,再水化问题是当您导航到一个页面时,一旦返回到上一个页面,您将看不到某些组件,因为它们不会由于此问题而呈现(再水化)
步骤:
- 在项目中的任意位置创建一个文件,并将其命名为
useCollPosition.js
- 粘贴以下代码:
import { useLayoutEffect, useRef } from 'react';
const isBrowser = typeof window !== `undefined`;
const getScrollPosition = ({ element, useWindow }) => {
if (!isBrowser) return { x: 0, y: 0 };
const target = element ? element.current : document.body,
position = target.getBoundingClientRect();
return useWindow
? { x: window.scrollX, y: window.scrollY }
: { x: position.left, y: position.top };
};
export const useScrollPosition = (effect, deps, element, useWindow, wait) => {
const position = useRef(getScrollPosition({ useWindow }));
let throttleTimeout = null;
const callBack = () => {
const currentPosition = getScrollPosition({ element, useWindow });
effect({ previousPosition: position.current, currentPosition: currentPosition });
position.current = currentPosition;
throttleTimeout = null;
};
useLayoutEffect(() => {
const handleScroll = () => {
if (wait && !throttleTimeout) throttleTimeout = setTimeout(callBack, wait);
else callBack();
};
window.addEventListener(`scroll`, handleScroll);
return () => window.removeEventListener(`scroll`, handleScroll);
}, deps);
};
- 将其导入到所需组件中,如下所示:
import { useScrollPosition } from '/path/to/useScrollPosition/useScrollPosition';
- 使用它
如果我将代码放在这里,是否还需要包含script.js:在script.js中?不,您可以使用自定义钩子删除脚本。您只需要创建一个文件来放置代码并将其导入到您的组件中,所以我将把它作为组件导入?没有URL,里面的代码。。。您只需创建一个文件,将其命名为useWindowsSize.js
,粘贴代码,然后将其导入组件中,如import{useWindowsSize}from”/path/to/useWindowsSize.js“
我更新了上面的问题,请告诉我是否正确
import { useLayoutEffect, useRef } from 'react';
const isBrowser = typeof window !== `undefined`;
const getScrollPosition = ({ element, useWindow }) => {
if (!isBrowser) return { x: 0, y: 0 };
const target = element ? element.current : document.body,
position = target.getBoundingClientRect();
return useWindow
? { x: window.scrollX, y: window.scrollY }
: { x: position.left, y: position.top };
};
export const useScrollPosition = (effect, deps, element, useWindow, wait) => {
const position = useRef(getScrollPosition({ useWindow }));
let throttleTimeout = null;
const callBack = () => {
const currentPosition = getScrollPosition({ element, useWindow });
effect({ previousPosition: position.current, currentPosition: currentPosition });
position.current = currentPosition;
throttleTimeout = null;
};
useLayoutEffect(() => {
const handleScroll = () => {
if (wait && !throttleTimeout) throttleTimeout = setTimeout(callBack, wait);
else callBack();
};
window.addEventListener(`scroll`, handleScroll);
return () => window.removeEventListener(`scroll`, handleScroll);
}, deps);
};
import { useLayoutEffect, useRef } from 'react';
const isBrowser = typeof window !== `undefined`;
const getScrollPosition = ({ element, useWindow }) => {
if (!isBrowser) return { x: 0, y: 0 };
const target = element ? element.current : document.body,
position = target.getBoundingClientRect();
return useWindow
? { x: window.scrollX, y: window.scrollY }
: { x: position.left, y: position.top };
};
export const useScrollPosition = (effect, deps, element, useWindow, wait) => {
const position = useRef(getScrollPosition({ useWindow }));
let throttleTimeout = null;
const callBack = () => {
const currentPosition = getScrollPosition({ element, useWindow });
effect({ previousPosition: position.current, currentPosition: currentPosition });
position.current = currentPosition;
throttleTimeout = null;
};
useLayoutEffect(() => {
const handleScroll = () => {
if (wait && !throttleTimeout) throttleTimeout = setTimeout(callBack, wait);
else callBack();
};
window.addEventListener(`scroll`, handleScroll);
return () => window.removeEventListener(`scroll`, handleScroll);
}, deps);
};
import { useScrollPosition } from '/path/to/useScrollPosition/useScrollPosition';