移至Next.js和Webpack

2023-10-11 05:30
文章标签 js webpack next 移至

本文主要是介绍移至Next.js和Webpack,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

具有样式组件和宗地的简单流式SSR React

通过我的Adobe Stock Photo许可进行照片。

当我第一次使用Next.js时,我最喜欢的一件事是它使Webpack所需的大量样板几乎消失了。 它还规定了简单,合乎逻辑的约定,如果您遵循这些约定,则可以轻松获得成功。

与以前创建服务器端渲染(SSR)React应用程序的复杂性相比,我发现它在简化性方面有了巨大的进步。

但是,去年年初,我意识到可以在与核心React API保持紧密联系的同时为我解决相同问题的新工具。

我对Next.js的最大了解之一是它的自定义路由-尽管使用简单-替代的React Router确实很棒,并且附带了很棒的动画库,我喜欢创建漂亮的,易于使用的东西!

因此,在2018年初,我放弃了Next.js和Webpack,以寻求“更接近金属”的东西,并开始使用Parcel构建React应用。

在本文中,我想向您展示如何使用Parcel构建应用程序以创建具有样式组件的流服务器端渲染的React应用程序。

如果您想知道让我感到兴奋还是尚未尝试过Parcel的东西-Parcel是Javascript Land中较新的模块捆绑包。

您认为:“这是我必须学习的另一种工具”。

没事 包裹不会那样滚动。 这是零配置。

它只是工作。

您可以导入.css文件,图像以及任何其他所需的文件,它的工作原理与您期望的完全相同。

这使得制作使用React生态系统中所有最新和最出色功能的通用应用程序变得非常容易,包括代码拆分,流式渲染,甚至是差分捆绑,这使得轻松获得最新的性能优化变得非常容易!

我想使用新的React lazy和Suspense API来实现代码拆分,但是,服务器端仍不支持它,因此我们将使用类似的替代方法。

在某些情况下仍可能略高于 Next.js更冗长,但为我用的情况下,我更喜欢额外的定制。 我想如果您对工具进行了评估已经有一段时间了,就会发现事情变得如此简单,您会感到惊讶。

旨在使您能够继续学习并获得一个不错的新样板。

我始终有一个个人目标,就是要使东西尽可能轻便。 如果这不是SSR,我建议您完全检出Hyperapp而不是React。 我为Shopify插件构建了一个非常酷的JS SDK,该插件在整个夏天都为使用它的机器学习提供了建议。

那么,我们还等什么呢? 让我们开始吧!

1.设定

首先,使用以下目录结构创建一个新项目-一个文件,两个文件夹。

- app/
- server/
.gitignore

我们将使用mkdir创建一个名为stream-all-the-things的目录。 然后,我们将进入该目录,并创建一个名为app的文件夹和一个名为server的文件夹。 最后,我们将使用touch创建我们的.gitignore文件。

这是一个快速的小片段。 随意键入每一行或复制并

将整个内容粘贴到您的终端中。

mkdir stream-all-the-things && cd stream-all-the-things
mkdir app
mkdir server
touch .gitignore

这是我们的.gitignore的内容

node_modules
*.log
.cache
dist

接下来,让我们安装所需的依赖项。

npm initnpm i --save react react-dom react-router styled-components react-helmet- async @ 0.2 .0 react-imported-componentnpm i --save-dev parcel-bundler react-hot-loader

好了,有一点要在那儿解压缩。 尽管您之前从未见过很多。

您之前可能已经使用过基本的依赖项... reactreact-domreact-router 。 然后,我们还使用样式化组件来利用其流式渲染支持 。 除了样式组件是支持流渲染的CSS-in-JS库之外,我已经更喜欢styled-components ! 它自以为是的方法有助于实施最佳实践以及对CSS开发人员友好。

react-helmet-async是与流SSR一起使用的流行库react-helmet的异步版本。 它允许您在导航时更改HTML文档开头的信息。 例如,更新页面title

另外,我们有parcel-bundler ,可以捆绑, cross-env来解决Windows中的问题, nodemon ,用于开发服务器, react-hot-loader用于开发客户端, rimraf用于清理。

2.包裹开发模式

似乎我们的目标是如何发展,让我们从发展模式开始。

package.json的脚本部分添加一个dev脚本。

"scripts" : {"dev" : "parcel app/index.html"
}

使用Parcel,您可以简单地为其指定应用程序的入口点,作为开始开发的唯一参数。

现在,让我们创建我们引用的app/index.html文件。

<!DOCTYPE html>
< html > <head><meta charset="UTF-8"><meta content="text/html;charset=utf-8" http-equiv="Content-Type"><meta content="utf-8" http-equiv="encoding"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">      </head><body><div id="app"></div><script id="js-entrypoint" src="./client.js"></script></body>
</html>

在其中,另一个对我们尚未创建的文件的引用: client.js

这是我们客户应用程序的入口点。 换句话说,就是起点。 这是将渲染初始树的地方。

让我们创建app/client.js ,然后将其分解。

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { HelmetProvider } from 'react-helmet-async' ;const element = document .getElementById( 'app' )const app = (< HelmetProvider > <App /> </ HelmetProvider >
)ReactDOM.render(app, element)// Enable Hot Module Reloading
if ( module .hot) {module .hot.accept();
}

最后,在我们可以测试任何东西之前,我们还需要app/App.jsx

import React from 'react'
import Helmet from 'react-helmet-async'
const App = () => (< React.Fragment > <Helmet><title>Home Page</title></Helmet><div>Follow me at <a href="https://medium.com/@patrickleet">@patrickleet</a></div> </ React.Fragment >
)
export default App

现在,您应该可以运行npm run dev来启动您的开发服务器,并重新加载热代码!

➜  npm run dev
> stream-all-the-things@ 1.0 .0 dev Users/me/dev/patrickleet/stream-all-the-things
> parcel app/index.html
Server running at http: //localhost:1234
✨  Built in 192 ms.

让我们来看看!

因为您不是我,所以尝试将页面更新为您自己的链接,并请注意您无需重新加载即可查看更改!

3.添加一些样式

我混合使用了全局样式和样式化组件。

让我们添加一些基本的重置和样式,以及定义几个有用的CSS变量,这些变量将在数学上帮助我们进行即将来临的设计冒险。

创建一个文件styles.js

import { createGlobalStyle } from 'styled-components'
export const GlobalStyles = createGlobalStyle `
/* Base 10 typography scale courtesty of @wesbos 1.6rem === 16px */
html {font-size: 10px;
}
body {font-size: 1.6rem;
}
/* Relative Type Scale */
/* https://blog.envylabs.com/responsive-typographic-scales-in-css-b9f60431d1c4 */
:root {--step-up-5: 2em;--step-up-4: 1.7511em;--step-up-3: 1.5157em;--step-up-2: 1.3195em;--step-up-1: 1.1487em;/* baseline: 1em */--step-down-1: 0.8706em;--step-down-2: 0.7579em;--step-down-3: 0.6599em;--step-down-4: 0.5745em;--step-down-5: 0.5em;/* Colors */--header: rgb(0,0,0);
}
/* https://css-tricks.com/snippets/css/system-font-stack/ */
/* Define the "system" font family */
/* Fastest loading font - the one native to their device */
@font-face {font-family: system;font-style: normal;font-weight: 300;src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), local(".LucidaGrandeUI"), local("Ubuntu Light"), local("Segoe UI Light"), local("Roboto-Light"), local("DroidSans"), local("Tahoma");
}
/* Modern CSS Reset */
/* https://alligator.io/css/minimal-css-reset/ */
body, h1, h2, h3, h4, h5, h6, p, ol, ul, input[type=text], input[type=email], button {margin: 0;padding: 0;font-weight: normal;
}
body, h1, h2, h3, h4, h5, h6, p, ol, ul, input[type=text], input[type=email], button {font-family: "system"
}
*, *:before, *:after {box-sizing: inherit;
}
ol, ul {list-style: none;
}
img {max-width: 100%;height: auto;
}
/* Links */
a {text-decoration: underline;color: inherit;
&.active {text-decoration: none;}
}
`

app/App.jsx导入GlobalStyles

import { Global Styles } from './styles'

然后更改App以呈现GlobalStyles组件。

const App = () => (< div > <GlobalStyles /> Follow me at  <a href="https://medium.com/@patrickleet">@patrickleet</a> </ div >
)

您的应用看起来不那么难看。

4.路由

接下来我们需要使页面变得简单。

让我们添加React Router。

在您的客户端中,我们需要从React Router导入BrowserRouter ,然后将其包装在一起。

app/client.js

import { BrowserRouter } from 'react-router-dom'
// ...
const app = (< HelmetProvider > <BrowserRouter><GlobalStyles /><App /></BrowserRouter> </ HelmetProvider >
)

现在在app/App.jsx我们需要将当前内容提取到一个新组件中,然后通过路由器加载。 让我们从创建一个新页面开始,使用与App.jsx当前几乎相同的内容。

创建app/pages/Home.jsx

import React from 'react'
import Helmet from 'react-helmet-async'
const Home = () => (< React.Fragment > <Helmet><title>Home Page</title></Helmet><div>Follow me at <a href="https://medium.com/@patrickleet">@patrickleet</a></div> </ React.Fragment >
)
export default Home

然后,修改App.jsx以具有以下内容:

import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import Home from './pages/Home'
const App = () => (< React.Fragment > <GlobalStyles /><Switch><Route exact path="/" component={Home} /><Redirect to="/" /></Switch></React.Fragment>
)
export default App

现在,当我们运行我们的应用程序时,它的外观应与之前相同,只是这次它是根据路由/的匹配通过我们的路由器渲染的。

在继续之前,让我们添加第二条路线,但这一次是“代码拆分”。

让我们创建第二个页面, app/pages/About.jsx

import React from 'react'
import Helmet from 'react-helmet-async'
const About = () => (< React.Fragment > <Helmet><title>About Page</title></Helmet><div>This is the about page</div> </ React.Fragment >
)
export default About

app/pages/Loading.jsx有一个加载组件:

import React from 'react'
const Loading = () => (< div >Loading...</ div >
)
export default Loading

最后是app/pages/Error.jsx的错误组件:

import React from 'react'
const Error = () => (< div >Error!</ div >
)
export default Error

为了导入它,不幸的是,我想使用新的React.lazy和Suspense API,尽管它们将在客户端上运行,但是一旦进入服务器端渲染,我们会发现ReactDomServer尚不支持Suspense。

相反,我们将依赖于另一个名为react-imported-component的库,它将与客户端和服务器端渲染的应用程序一起使用。

这是我们更新的app/App.jsx

import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom' ;
import importComponent from 'react-imported-component' ;
import Home from './pages/Home.jsx'
import LoadingComponent from './pages/Loading'
import ErrorComponent from './pages/Error'
const About = importComponent( () => import ( "./pages/About" ), {LoadingComponent,ErrorComponent
});
const App = () => (< React.Fragment > <GlobalStyles /><Switch><Route exact path="/" component={Home} /><Route exact path="/about" render={() => <About />} /><Redirect to="/" /></Switch></React.Fragment>
)
export default App

现在,我们应该能够导航到/ about来查看我们的新页面。 如果您快速浏览,您将看到页面内容之前出现正在加载...。

5.布局和导航

现在,我们需要在地址栏中输入路线进行导航,这并不理想。 在转到“服务器端渲染”之前,让我们为页面添加一个通用布局,并添加一个带有导航功能的标题。

让我们从Header开始,以便我们获得clickin'。

创建app/components/Header.jsx

import React from 'react' ;
import styled from 'styled-components'
import { NavLink } from 'react-router-dom' ;
const Header = styled.header `z-index: 100;position: fixed;top: 0;left: 0;right: 0;max-width: 90vw;margin: 0 auto;padding: 1em 0;display: flex;justify-content: space-between;align-items: center;
`
const Brand = styled.h1 `font-size: var(--step-up-1);
`
const Menu = styled.ul `display: flex;justify-content: flex-end;align-items: center;width: 50vw;
`
const MenuLink = styled.li `margin-left: 2em;text-decoration: none;
`
export default () => (< Header > <Brand>Stream all the things!</Brand><Menu><MenuLink><NavLink to="/"exact activeClassName="active">Home</NavLink></MenuLink><MenuLink><NavLink to="/about" exact activeClassName="active">About</NavLink></MenuLink></Menu> </ Header >
)

我们需要将其导入并将其放入我们的应用中。

这是更新的App.jsx

import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom' ;
import importComponent from 'react-imported-component' ;
import { GlobalStyles } from './styles'
import Header from './components/Header'
import Home from './pages/Home'
import LoadingComponent from './pages/Loading'
import ErrorComponent from './pages/Error'
const About = importComponent( () => import ( "./pages/About" ), {LoadingComponent,ErrorComponent
});
const App = () => (< React.Fragment > <GlobalStyles /><Header /><Switch><Route exact path="/" component={Home} /><Route exact path="/about" render={() => <About />} /><Redirect to="/" /></Switch></React.Fragment>

我们还创建一个Page组件,每个页面都可以使用该组件来实现一致的Page样式。

创建app/components/Page.jsx

然后,在我们的四个页面中,导入新的Page组件,并用它替换每个页面中的包装React.Fragment。

这是Home

import React from 'react'
import Helmet from 'react-helmet-async'
import Page from '../components/Page.jsx'
const Home = () => (< Page > <Helmet><title>Home Page</title></Helmet><div>Follow me at <a href="https://medium.com/@patrickleet">@patrickleet</a></div> </ Page >
)
export default Home

并对“ About页面以及“错误”和“加载”页面执行相同的操作。

我们的应用程序开始看起来更好了!

显然,可以通过无数种方式来设置此应用程序的样式,因此,我将使练习变得更漂亮。

6.流式服务器端渲染

我们达到目标的下一步是添加流服务器端渲染。 如果您一直在关注,您会发现到目前为止,我们已经创建了一个静态客户端应用程序。

从客户端到同构需要在服务器上创建一个新的入口点,然后将加载与我们的客户端入口点加载的相同的App组件。

我们还将需要其他几个新的npm软件包:

npm i --save llog pino express through cheerio 
npm i --save-dev concurrently rimraf nodemon @babel/polyfill cross-env

让我们创建server / index.js:

import path from 'path'
import express from 'express'
import log from 'llog'
import ssr from './lib/ssr'
const app = express()
// Expose the public directory as /dist and point to the browser version
app.use( '/dist/client' , express.static(path.resolve(process.cwd(), 'dist' , 'client' )));
// Anything unresolved is serving the application and let
// react-router do the routing!
app.get( '/*' , ssr)
// Check for PORT environment variable, otherwise fallback on Parcel default port
const port = process.env.PORT || 1234 ;
app.listen(port, () => {log.info( `Listening on port ${port} ...` );
});

好的,这里有几件事要解压:

  1. 我们正在使用快递-它很可能是任何其他服务器。 我们实际上并没有做太多事情,因此转换为您选择的服务器应该不难。
  2. 我们正在为/ dist / clients目录设置一个静态文件服务器。 我们目前没有建立生产资产,但是当我们建立资产时,我们可以将它们放在那里。
  3. 其他所有路线都将进入ssr。 不用理会服务器上的路由,我们只需执行React Router所做的任何事情即可。

让我们创建ssr函数。 这可能比本教程的其余部分要复杂得多,但这只是需要做一次,然后基本上不做任何事情。

在继续之前,让我们看一下需要创建的脚本。

"scripts" : {"dev" : "npm run generate-imported-components && parcel app/index.html" ,"dev:server" : "nodemon -e js,jsx,html --ignore dist --ignore app/imported.js --exec 'npm run build && npm run start'" ,"start" : "node dist/server""build" : "rimraf dist && npm run generate-imported-components && npm run create-bundles" ,"create-bundles" : "concurrently \"npm run create-bundle:client\" \"npm run create-bundle:server\"" ,"create-bundle:client" : "cross-env BABEL_ENV=client parcel build app/index.html -d dist/client --public-url /dist/client" ,"create-bundle:server" : "cross-env BABEL_ENV=server parcel build server/index.js -d dist/server --public-url /dist --target=node" ,"generate-imported-components" : "imported-components app app/imported.js" ,"start" : "node dist/server"
}

现在还有很多。 我突出显示了名称,以使其更易于阅读。 在较高的级别上,我们添加了构建脚本来生成一个包含有关导入组件信息的文件,以及一个可以使用宗地同时构建客户端和服务器捆绑包的构建脚本。

现在,对于导入的组件,我们还需要一个.babelrc文件。 也许在接下来的几个月中,这种情况将会改变。

{"env" : {"server" : {"plugins" : [ "react-imported-component/babel" , "babel-plugin-dynamic-import-node" ]},"client" : {"plugins" : [[ "react-imported-component/babel" ]]}}
}

有了这一点,我们要解决两个主要问题。

创建SSR中间件为SSR重新使用客户端HTML数据并从中解析生成的src名称

创建server/lib/ssr.js

import React from 'react'
import { renderToNodeStream } from 'react-dom/server'
import { HelmetProvider } from 'react-helmet-async'
import { StaticRouter } from 'react-router-dom'
import { ServerStyleSheet } from 'styled-components'
import { printDrainHydrateMarks } from 'react-imported-component' ;
import log from 'llog'
import through from 'through'
import App from '../../app/App'
import { getHTMLFragments } from './client'
// import { getDataFromTree } from 'react-apollo';
export default (req, res) => {const context = {};const helmetContext = {};
const app = (< HelmetProvider context = {helmetContext} > <StaticRouterlocation={req.originalUrl}context={context}><App /></StaticRouter> </ HelmetProvider >);try {// If you were using Apollo, you could fetch data with this// await getDataFromTree(app);const sheet = new ServerStyleSheet()const stream = sheet.interleaveWithNodeStream(renderToNodeStream(sheet.collectStyles(app)))if (context.url) {res.redirect( 301 , context.url);} else {const [startingHTMLFragment,endingHTMLFragment] = getHTMLFragments({ drainHydrateMarks : printDrainHydrateMarks() })res.status( 200 )res.write(startingHTMLFragment)stream.pipe(through(function write ( data )  {this .queue(data)},function end ( )  {this .queue(endingHTMLFragment)this .queue( null )})).pipe(res)}} catch (e) {log.error(e)res.status( 500 )res.end()}
};

使用server/lib/client.js我们需要读取app/index.html文件,并将其分为两个块,使上面的流式传输更加容易。

import fs from 'fs' ;
import path from 'path' ;
import cheerio from 'cheerio' ;
export const htmlPath = path.join(process.cwd(), 'dist' , 'client' , 'index.html' );
export const rawHTML = fs.readFileSync(htmlPath).toString();
export const parseRawHTMLForData = ( template, selector = "#js-entrypoint" ) => {const $template = cheerio.load(template);let src = $template(selector).attr( 'src' )return {src}
}
const clientData = parseRawHTMLForData(rawHTML)
const appString = '<div id="app"\>'
const splitter = '###SPLIT###'
const [ startingRawHTMLFragment, endingRawHTMLFragment 
] = rawHTML.replace(appString, ` ${appString} ${splitter} ` ).split(splitter)
export const getHTMLFragments = ( { drainHydrateMarks } ) => {const startingHTMLFragment = ` ${startingRawHTMLFragment} ${drainHydrateMarks} `return [startingHTMLFragment, endingRawHTMLFragment]
}

这将通过服务器呈现我们的应用程序,但是如果不对客户端进行一些小改动,它将无法成功重新连接到客户端应用程序。

我们正在通过SSR功能提供“补水标记”,但尚未使用它们。

app/client.js进行以下修改:

1.导入rehydrateMarks importedComponents

import { rehydrateMarks } from 'react-imported-component' ;
import importedComponents from './imported' ; // eslint-disable-line

2.将ReactDOM.render(app, element)替换为:

// In production, we want to hydrate instead of render
// because of the server-rendering
if (process.env.NODE_ENV === 'production' ) {// rehydrate the bundle marksrehydrateMarks().then( () => {ReactDOM.hydrate(app, element);});
} else {ReactDOM.render(app, element);
}

并做了!

现在,当您运行npm run dev:servernpm run build && npm run start您将使用服务器端渲染!

结论

我承认,比Next.js还要多的样板,但希望它并没有那么压倒性,并且那里的内容是透明且可理解的。 公平地说,Next.js仍在为我们做更多的事情,例如预取组件。

但是,我仍然更喜欢这种方法,因为正在发生的事情没有什么神秘之处,Webpack配置已完全消失,并且很容易利用动画库来作为我将在练习中留下的React Router。

希望您发现这很有用!

如果您这样做,最好的帮助我的方法是给我一些鼓掌和/或分享!

最好,
帕特里克·李·斯科特

PS这是GitHub上的完整代码 。

PPS本文是系列文章的一部分。 看看下面的其他部分!

  • 第1部分:移至Next.js和Webpack
  • 第2部分:使用Docker开发Node.js的更好方法
  • 第3部分:增强Node.js的代码质量
  • 第4部分:100%代码覆盖率神话
  • 第5部分:两层(Docker多阶段构建)层的故事
  • 第6部分:引入机器人,让他们维护我们的代码

From: https://hackernoon.com/move-over-next-js-and-webpack-ba367f07545

这篇关于移至Next.js和Webpack的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/185863

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

使用JS/Jquery获得父窗口的几个方法(笔记)

<pre name="code" class="javascript">取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document);如题: $(selector, window.top.document);//获得顶级窗口里面的元素 $(

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

js react 笔记 2

起因, 目的: 记录一些 js, react, css 1. 生成一个随机的 uuid // 需要先安装 crypto 模块const { randomUUID } = require('crypto');const uuid = randomUUID();console.log(uuid); // 输出类似 '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

uuid.js 使用

相关代码 import { NIL } from "uuid";/** 验证UUID* 为空 则返回 false* @param uuid* @returns {boolean}*/export function MyUUIDValidate(uuid: any): boolean {if (typeof uuid === "string" && uuid !== NIL) { //uuid

js定位navigator.geolocation

一、简介   html5为window.navigator提供了geolocation属性,用于获取基于浏览器的当前用户地理位置。   window.navigator.geolocation提供了3个方法分别是: void getCurrentPosition(onSuccess,onError,options);//获取用户当前位置int watchCurrentPosition(