jquery重新渲染组件 js怎么实现页面重新渲染_Layout


Next.js 是一个轻量级的 React 服务端渲染应用框架:


https://nextjs.frontendx.cn/docsnextjs.frontendx.cn

1、什么是服务器渲染

后端先调用【数据库】,获得数据之后,将数据和页面元素进行拼装,组合成完整的 html 页面,再直接返回给浏览器,以便用户浏览。

整个渲染过程,是在服务器端执行!浏览器只负责去展示!

例如:


jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_02

服务器渲染


2、怎么判断这个网站是不是服务器渲染?

打开一个网站,右键,查看网页源代码,有与网站内容相关的代码,就是服务器渲染的。

3、什么是客户端渲染?

数据由浏览器通过 ajax 请求动态取得,再通过 js 将数据填充到 dom 元素最终展示到网页中。

例如:http://h5.ele.me/msite/


jquery重新渲染组件 js怎么实现页面重新渲染_js重新渲染div_03

客户端渲染

4、服务器渲染 VS 客户端渲染


jquery重新渲染组件 js怎么实现页面重新渲染_Layout_04


jquery重新渲染组件 js怎么实现页面重新渲染_js重新渲染div_05

看看就可以了

5、什么是 next.js ?

Next.js 是一个轻量级的 React 服务端渲染应用框架。

Next.js 使 React 应用 更简单。

安装:


npm install --save next react react-dom


初始化一个 npm 的项目(即初始化一个 package.json 文件):


npm init -Y


jquery重新渲染组件 js怎么实现页面重新渲染_Layout_06

此时的项目结构

在根目录创建一个 :

pages 文件 --> index.js 文件


jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_07


将下面脚本添加到 package.json 中:


{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}


即:


{  
  "name": "next",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "next": "^9.3.6",
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  },
  "devDependencies": {},
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "author": "",
  "license": "ISC"
}


index.js :(有状态组件)


import React, { Component } from 'react'

export default class Index extends Component {
    render() {
        return (
            <div>
                <h1>hello world</h1>
            </div>
        )
    }
}


这个组件还有更简单的写法:(无状态组件)


export default () => (
    <div>
        <h1>hello world!!!</h1>
    </div>
)


运行程序:


npm run dev


jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_08

默认打开 3000 端口

当我们在 index.js 文件中修改一下内容,再看 localhost:3000

热替换!!——没有刷新就显示出来了

6、什么是 react 同构!!???

客户端与服务器端使用相同的组件,使用同一份代码。

服务器端:至负责首次渲染。

客户端:负责行为和交互等等。(比如点击事件)


jquery重新渲染组件 js怎么实现页面重新渲染_Layout_09


7、使用 CSS / Sass / Less / Stylus files 样式

  • @zeit/next-css
  • @zeit/next-sass
  • @zeit/next-less
  • @zeit/next-stylus

@zeit/next-csswww.npmjs.com

jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_10


安装:


npm install --save @zeit/next-css


配置文件:


// next.config.js
const withCSS = require('@zeit/next-css')
module.exports = withCSS()


8、静态文件服务(如图像)

在根目录下新建文件夹叫static。代码可以通过/static/来引入相关的静态资源。


export default () => <img src="/static/my-image.png" alt="my image" />


9、定制 head

index.js :


import Head from 'next/head'

export default () => (
    <div>
        <Head>
            <title>next 教程</title>
            <meta charSet="utf-8" />
        </Head>
        <p>Hello world!</p>
    </div>
)


jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_11


jquery重新渲染组件 js怎么实现页面重新渲染_Layout_12


头部/底部


jquery重新渲染组件 js怎么实现页面重新渲染_Layout_13

目录结构

Layout .js:


import Head from 'next/head'

export default ({children}) => (
    <div>
        <Head>
            <title>头部测试</title>
        </Head>
        {children}
        <footer>
            版权所有.未经许可.不可转载
        </footer>  
    </div>
)


index.js:


import Layout  from './components/layout'

export default () => (
    <Layout>
        <div>
            <h1>Hello world!</h1>
        </div>
    </Layout>
)


list.js:


import React, { Component } from 'react'
import '../styles/list.css'
import Layout  from './components/layout'

export default class List extends Component {
    state = {
        list:[ "a" , "b" , "c" ]
    }
    render() {
        return (
            <Layout>
                <div>
                    <ul>
                        {
                            this.state.list.map(item =>(
                                <li>{item}</li>
                            ))
                        }
                    </ul>
                </div>
            </Layout>
        )
    }
}


jquery重新渲染组件 js怎么实现页面重新渲染_js重新渲染div_14

结果·

10、数据获取和生命周期

如果你需要一个有状态、生命周期或有初始数据的 React 组件(而不是无状态函数)

如下所示:


import React from 'react'

export default class extends React.Component {
//状态
  static async getInitialProps({ req }) {
    const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
    return { userAgent }
  }
//方法,返回
  render() {
    return (
      <div>
        Hello World {this.props.userAgent}
      </div>
    )
  }

}


页面渲染时加载数据,我们使用了一个异步方法 getInitialProps 。它能异步获取 JS 普通对象,并绑定在 props 上。

当服务渲染时,getInitialProps 将会把数据序列化,就像 JSON.stringify 。所以确保getInitialProps 返回的是一个普通 JS 对象,而不是 Date, Map 或 Set 类型。

当页面初始化加载时,getInitialProps 只会加载在服务端没有跨域的限制

只有当路由跳转(Link组件跳转或 API 方法跳转)时,客户端才会执行 getInitialProps。

注意:getInitialProps 将不能使用在子组件中。只能使用在 pages 页面组件中。

getInitialProps 的属性:

  • pathname ------- URL 的 path 部分
  • query ------------ URL 的 query 部分,并被解析成对象
  • asPath ----------- 显示在浏览器中的实际路径(包含查询部分),为String类型
  • req --------------- HTTP 请求对象 (只有服务器端有)
  • res ---------------- HTTP 返回对象 (只有服务器端有)
  • jsonPageRes ----- 获取数据响应对象 (只有客户端有)
  • err ---------------- 渲染过程中的任何错误

https://m.maizou.com/v5/#/filmsm.maizou.com


jquery重新渲染组件 js怎么实现页面重新渲染_jquery重新渲染组件_15

如果接口可以用

jquery重新渲染组件 js怎么实现页面重新渲染_js重新渲染div_16

它的结果


11、路由

路由的基本功能:next 默认按照文件结构(路径),进行页面跳转!

路由又分为:
基本路由:按照文件结构,进行页面跳转。(基本路由跳转又分为:link 跳转和编程式跳转。)
动态路由:

路由页面跳转的 3 种方式:
link 跳转
编程式跳转
参数传递——路由跳转一般会传递一些参数

<Link>组件实现客户端的路由切换:

引入


import Link from 'next/link'


layout.js:


import Head from 'next/head'
import Link from 'next/link'

export default ({children}) => (
    <div>
        <Head>
            <title>头部测试</title>
        </Head>
        <div>
            <Link href='/'>主页</Link> |
            <Link href='/list'>列表</Link> |
            <Link href='/nestStyle'>内联样式</Link>
        </div>
        {children}
        <footer>
            版权所有.未经许可.不可转载
        </footer>  
    </div>
)


index.js:


import Layout  from './components/layout'

export default () => (
    <Layout>
        <div>
            <h1>Hello world!</h1>
        </div>
    </Layout>
)


list.js:


import React, { Component } from 'react'
import Layout  from './components/layout'
import '../styles/list.css'
import Router from 'next/router'

export default class List extends Component {
    state = {
        list:[ "a" , "b" , "c" ]
    }
    render() {
        return (
            <Layout>
                <div>
                    <ul>
                        {
                            this.state.list.map((item, index) =>(
                                <li key={index} onClick={() => Router.push('/detail?arg=' + item)}>{item}</li>
                            ))
                        }
                    </ul>
                </div>
            </Layout>
        )
    }
}


注意: <Link>支持任何有 onClick事件的组件。
如果你不包含 <a>标签,它仅给组件添加 onClick事件,而不会添加 href属性!!

所以想要 list 页面也能跳转,需要:

nextStyle.js:


import React, { Component } from 'react'
import Layout  from './components/layout'

export default class NextStyle extends Component {
    render() {
        return (
            <Layout>
                <div>
                    <style jsx>{`
                        h1 {
                            background-color: blue;
                        }
                    `}</style>
                    <h1>这里是内联样式!!(但不推荐这种写法)</h1>
                </div>
            </Layout>
        )
    }
}


这样就实现了路由传参

Router.push('/detail?arg='+ item)}
但 push 支持对象形式的

替换路由:

<Link>组件默认将新 url 推入路由栈中。可以使用replace属性来防止添加新输入。


// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href="/about" replace>
      <a>here</a>
    </Link>{' '}
    to read more
  </div>


暴露 href 给子元素:


import Link from 'next/link'
import Unexpected_A from 'third-library'

export default ({ href, name }) =>
  <Link href={href} passHref>
    <Unexpected_A>
      {name}
    </Unexpected_A>
  </Link>


禁止滚动到页面顶部:

<Link>的默认行为就是滚到页面顶部。

当有 hash 定义时(#),页面将会滚动到对应的 id 上,就像<a>标签一样。

为了预防滚动到顶部,可以给<Link>scroll={false}属性。


<Link scroll={false} href="/?counter=10"><a>Disables scrolling</a></Link>
<Link href="/?counter=10"><a>Changes with scrolling to top</a></Link>


命令式:

也可以用next/router实现客户端路由切换。


import Router from 'next/router'

export default () =>
  <div>
    Click <span onClick={() => Router.push('/about')}>here</span> to read more
  </div>


拦截器 popstate

有些情况(比如使用custom router),你可能想监听popstate,在路由跳转前做一些动作。 比如,你可以操作 request 或强制 SSR 刷新。


import Router from 'next/router'

Router.beforePopState(({ url, as, options }) => {
  // I only want to allow these two routes!
  if (as !== "/" || as !== "/other") {
    // Have SSR render bad routes as a 404.
    window.location.href = as
    return false
  }

  return true
});


如果你在 beforePopState中返回 false, Router将不会执行 popstate事件。

Router对象的 API 如下:

  • route - 当前路由的String类型
  • pathname - 不包含查询内容的当前路径,为String类型
  • query - 查询内容,被解析成Object类型. 默认为{}
  • asPath - 展现在浏览器上的实际路径,包含查询内容,为String类型
  • push(url, as=url) - 页面渲染第一个参数 url 的页面,浏览器栏显示的是第二个参数 url
  • replace(url, as=url) - performs a replaceState call with the given url
  • beforePopState(cb=function) - 在路由器处理事件之前拦截.

pushreplace 函数的第二个参数as,是为了装饰 URL 作用。如果你在服务器端设置了自定义路由将会起作用。

URL 对象用法:

pushreplace可接收的 URL 对象(<Link>组件的 URL 对象一样)来生成 URL。


import Router from 'next/router'

const handler = () =>
  Router.push({
    pathname: '/about',
    query: { name: 'Zeit' }
  })

export default () =>
  <div>
    Click <span onClick={handler}>here</span> to read more
  </div>


路由事件:

可以监听路由相关事件。 下面是事件支持列表:

  • routeChangeStart(url) - 路由开始切换时触发
  • routeChangeComplete(url) - 完成路由切换时触发
  • routeChangeError(err, url) - 路由切换报错时触发
  • beforeHistoryChange(url) - 浏览器 history 模式开始切换时触发
  • hashChangeStart(url) - 开始切换 hash 值但是没有切换页面路由时触发
  • hashChangeComplete(url) - 完成切换 hash 值但是没有切换页面路由时触发

这里的 url是指显示在浏览器中的 url。如果你用了 Router.push(url, as)(或类似的方法),那浏览器中的 url 将会显示 as 的值。

正确使用路由事件routeChangeStart的例子:


const handleRouteChange = url => {
  console.log('App is changing to: ', url)
}

Router.events.on('routeChangeStart', handleRouteChange)


如果你不想长期监听该事件,你可以用off事件去取消监听:


Router.events.off('routeChangeStart', handleRouteChange)


如果路由加载被取消(比如快速连续双击链接):


Router.events.on('routeChangeError', (err, url) => {
  if (err.cancelled) {
    console.log(`Route to ${url} was cancelled!`)
  }
})