js重新渲染div_服务器渲染知识大全(1)

48f664363371ade512c264096f5f6283.png

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

https://nextjs.frontendx.cn/docs​nextjs.frontendx.cn

1、什么是服务器渲染

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

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

例如:http://www.cnblogs.com/cate/design/

d2e0802f46534a7d2566625aa82be459.png
服务器渲染

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

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

3、什么是客户端渲染?

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

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

33647b832886356c4bb1bee699b17c54.png
客户端渲染

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

a4b490d656e50802125e2d61c857043e.png

18eecc022c7c7953a998b7898b0d56f0.png
看看就可以了

5、什么是 next.js ?

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

Next.js 使 React 应用 更简单。

安装:

npm install --save next react react-dom

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

npm init -Y

0e0261e93d0f078d15039b4b9b0d6743.png
此时的项目结构

在根目录创建一个 :

pages 文件 --> index.js 文件

fff1b1849a2839278285f73feb8086df.png

将下面脚本添加到 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

2fc00056f2ae02fcf76428639a0a55db.png
默认打开 3000 端口

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

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

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

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

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

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

8425818a1f534e2c3b77983a13ac6dde.png

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

  • @zeit/next-css
  • @zeit/next-sass
  • @zeit/next-less
  • @zeit/next-stylus
@zeit/next-css​www.npmjs.com
d3f87bd6a5da23efa2313758f6150d18.png

安装:

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>
)

fdf9cf391f2be48ad6682f0ee0d215bc.png

9749280d737c5ff73701366f146f1f72.png

头部/底部

1442fa58f4c01fc042d7d7211e5755aa.png
目录结构

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>
        )
    }
}

6c3e5a1d6825f7fa38eb7b0b6e8cb8d4.png
结果·

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/#/films​m.maizou.com

261daf6d4669d9c568126636418b6a3c.png
如果接口可以用

8923080eeba596dd836bfa395f86b509.png
它的结果

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!`)
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值