|
| 1 | +# 基本用法 |
| 2 | + |
| 3 | +## 安装 |
| 4 | + |
| 5 | +```bash |
| 6 | +npm install vue vue-server-renderer --save |
| 7 | +``` |
| 8 | + |
| 9 | +我们将在整个指南中使用 NPM,但是还可以随意使用 [Yarn](https://yarnpkg.com/en/)。 |
| 10 | + |
| 11 | +#### 注意 |
| 12 | + |
| 13 | +- 推荐使用 Node.js 版本 6+。 |
| 14 | +- `vue-server-renderer` 和 `vue` 必须匹配版本。 |
| 15 | +- `vue-server-renderer` 依赖一些 Node.js 原生模块,因此只能在 Node.js 中使用。我们可能会提供一个更简单的构建,可以在将来在其他「JavaScript 运行时(runtime)」运行。 |
| 16 | + |
| 17 | +## 渲染一个 Vue 实例 |
| 18 | + |
| 19 | +```js |
| 20 | +// 第 1 步:创建一个 Vue 实例 |
| 21 | +const Vue = require('vue') |
| 22 | +const app = new Vue({ |
| 23 | + template: `<div>Hello World</div>` |
| 24 | +}) |
| 25 | +// 第 2 步:创建一个 renderer |
| 26 | +const renderer = require('vue-server-renderer').createRenderer() |
| 27 | +// 第 3 步:将 Vue 实例渲染为 HTML |
| 28 | +renderer.renderToString(app, (err, html) => { |
| 29 | + if (err) throw err |
| 30 | + console.log(html) |
| 31 | + // => <div data-server-rendered="true">Hello World</div> |
| 32 | +}) |
| 33 | +``` |
| 34 | + |
| 35 | +## 与服务器集成 |
| 36 | + |
| 37 | +在 Node.js 服务器中使用时相当简单直接,例如 [Express](https://expressjs.com/): |
| 38 | + |
| 39 | +```bash |
| 40 | +npm install express --save |
| 41 | +``` |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +```js |
| 46 | +const Vue = require('vue') |
| 47 | +const server = require('express')() |
| 48 | +const renderer = require('vue-server-renderer').createRenderer() |
| 49 | +server.get('*', (req, res) => { |
| 50 | + const app = new Vue({ |
| 51 | + data: { |
| 52 | + url: req.url |
| 53 | + }, |
| 54 | + template: `<div>访问的 URL 是: {{ url }}</div>` |
| 55 | + }) |
| 56 | + renderer.renderToString(app, (err, html) => { |
| 57 | + if (err) { |
| 58 | + res.status(500).end('Internal Server Error') |
| 59 | + return |
| 60 | + } |
| 61 | + res.end(` |
| 62 | + <!DOCTYPE html> |
| 63 | + <html lang="en"> |
| 64 | + <head><title>Hello</title></head> |
| 65 | + <body>${html}</body> |
| 66 | + </html> |
| 67 | + `) |
| 68 | + }) |
| 69 | +}) |
| 70 | +server.listen(8080) |
| 71 | +``` |
| 72 | + |
| 73 | +## 使用一个页面模板 |
| 74 | + |
| 75 | +当你在渲染 Vue 应用程序时,renderer 只从应用程序生成 HTML 标记(markup)。在这个示例中,我们必须用一个额外的 HTML 页面包裹容器,来包裹生成的 HTML 标记。 |
| 76 | + |
| 77 | +为了简化这些,你可以直接在创建 renderer 时提供一个页面模板。多数时候,我们会将页面模板放在特有的文件中,例如 `index.template.html`: |
| 78 | + |
| 79 | +```html |
| 80 | +<!DOCTYPE html> |
| 81 | +<html lang="en"> |
| 82 | + <head><title>Hello</title></head> |
| 83 | + <body> |
| 84 | + <!--vue-ssr-outlet--> |
| 85 | + </body> |
| 86 | +</html> |
| 87 | +``` |
| 88 | + |
| 89 | +注意 `<!--vue-ssr-outlet-->` 注释 -- 这里将是应用程序 HTML 标记注入的地方。 |
| 90 | + |
| 91 | +然后,我们可以读取和传输文件到 Vue renderer 中: |
| 92 | + |
| 93 | +```js |
| 94 | +const renderer = createRenderer({ |
| 95 | + template: require('fs').readFileSync('./index.template.html', 'utf-8') |
| 96 | +}) |
| 97 | +renderer.renderToString(app, (err, html) => { |
| 98 | + console.log(html) // will be the full page with app content injected. |
| 99 | +}) |
| 100 | +``` |
| 101 | + |
| 102 | +### 模板插值 |
| 103 | + |
| 104 | +模板还支持简单插值。给定如下模板: |
| 105 | + |
| 106 | +```html |
| 107 | +<html> |
| 108 | + <head> |
| 109 | + <!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) --> |
| 110 | + <title>{{ title }}</title> |
| 111 | + <!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) --> |
| 112 | + {{{ meta }}} |
| 113 | + </head> |
| 114 | + <body> |
| 115 | + <!--vue-ssr-outlet--> |
| 116 | + </body> |
| 117 | +</html> |
| 118 | +``` |
| 119 | + |
| 120 | +我们可以通过传入一个"渲染上下文对象",作为 `renderToString` 函数的第二个参数,来提供插值数据: |
| 121 | + |
| 122 | +```js |
| 123 | +const context = { |
| 124 | + title: 'hello', |
| 125 | + meta: ` |
| 126 | + <meta ...> |
| 127 | + <meta ...> |
| 128 | + ` |
| 129 | +} |
| 130 | +renderer.renderToString(app, context, (err, html) => { |
| 131 | + // page title will be "Hello" |
| 132 | + // with meta tags injected |
| 133 | +}) |
| 134 | +``` |
| 135 | + |
| 136 | +也可以与 Vue 应用程序实例共享 `context` 对象,允许模板插值中的组件动态地注册数据。 |
| 137 | + |
| 138 | +此外,模板支持一些高级特性,例如: |
| 139 | + |
| 140 | +- 在使用 `*.vue` 组件时,自动注入「关键的 CSS(critical CSS)」; |
| 141 | +- 在使用 `clientManifest` 时,自动注入「资源链接(asset links)和资源预加载提示(resource hints)」; |
| 142 | +- 在嵌入 Vuex 状态进行客户端融合(client-side hydration)时,自动注入以及 XSS 防御。 |
| 143 | + |
| 144 | +在之后的指南中介绍相关概念时,我们将详细讨论这些。 |
0 commit comments