目錄
第一部分基本介紹
1、前言
2、服務端渲染的優劣
3、SSR的實作原理
4、vue後端渲染主要外掛程式:vue-server-renderer
第二部分從零開始建立
2、前期准备
3、项目主目录搭建
4、脚手架其他目录介绍:
第三部分 mockjs和axios配合使用
3、简要介绍axios
首頁 web前端 js教程 使用vue-ssr如何實現服務端渲染

使用vue-ssr如何實現服務端渲染

Jun 12, 2018 pm 06:21 PM
vue 服務端渲染

這篇文章主要介紹了基於vue-ssr服務端渲染入門詳解,現在分享給大家,也為大家做個參考。

第一部分基本介紹

1、前言

服務端渲染實作原理機制:在服務端拿資料進行解析渲染,直接產生html片段返回給前端。然後前端可以透過解析後端回傳的html片段到前端頁面,大致有以下兩種形式:

1、伺服器透過模版引擎直接渲染整個頁面,例如java後端的vm模版引擎,php後端的smarty模版引擎。
2、服務渲染產生html程式碼區塊, 前端透過AJAX取得然後使用js動態加入。

2、服務端渲染的優劣

服務端渲染能夠解決兩大問題:

1、seo問題,有助於搜尋引擎蜘蛛抓取網站內容,利於網站的收錄和排名。
2、首屏載入過慢問題,例如現在成熟的SPA專案中,開啟首頁需要載入很多資源,透過服務端渲染可以加速首屏渲染。
同樣服務端渲染也會有弊端,主要是根據自己的業務場景來選擇適合方式,由於服務端渲染前端頁面,必將會給伺服器增加壓力。

3、SSR的實作原理

客戶端請求伺服器,伺服器根據請求位址獲得匹配的元件,在呼叫匹配到的元件返回Promise (官方是preFetch方法)來將所需的資料拿到。最後再透過

<script>window.__initial_state=data</script>
登入後複製

將其寫入網頁,最後將服務端渲染好的網頁回傳。

接下來客戶端會將vuex將寫入的 initial_state 替換為目前的全域狀態樹,再用這個狀態樹去檢查服務端渲染好的資料有沒有問題。遇到沒被服務端渲染的元件,再去發非同步請求拿資料。說穿了就是一個類似React的 shouldComponentUpdate 的Diff操作。

Vue2使用的是單向資料流,用了它,就可以透過 SSR 傳回唯一一個全域狀態, 並確認某個元件是否已經SSR過了。

4、vue後端渲染主要外掛程式:vue-server-renderer

由於virtual dom的引入,使得vue的服務端渲染成為了可能,以下是官方vue-server-renderer提供的渲染流程圖:

#可以看出vue的後端渲染分三個部分組成:頁面的原始碼(source),node層的渲染部分和瀏覽器端的渲染部分。

source分為兩種entry point,一個是前端頁面的入口client entry,主要是實例化Vue對象,將其掛載到頁面中;另外一個是後端渲染服務入口server entry,主要是控服務端渲染模組回調,回傳一個Promise對象,最後回傳一個Vue對象(經過測試,直接回傳Vue對像也是可以的);

前面的source部分就是業務開發的程式碼,開發完成之後透過webpack 進行構建,產生對應的bundle,這裡不再贅述client bundle,就是一個可在瀏覽器端執行的打包檔;這裡說下server bundle, vue2提供vue-server-renderer模組,模組可以提供兩種render : rendererer/bundleRenderer ,以下分別介紹下這兩種render。

renderer接收一個vue對象,然後進行渲染,這種對於簡單的vue對象,可以這麼做,但是對於復雜的項目,如果使用這種直接require一個vue對象,這個對於服務端代碼的結構和邏輯都不太友好,首先模組的狀態會一直延續在每個請求渲染請求,我們需要去管理和避免這次渲染請求的狀態影響到後面的請求,因此vue-server-renderer提供了另外一種渲染模式,透過一個bundleRenderer去做渲染。

bundleRenderer是較為複雜專案進行服務端渲染官方推薦的方式,透過webpack以server entry依照一定的要求打包產生一個server-bundle,它相當於一個可以給服務端用的app的打包壓縮文件,每一次呼叫都會重新初始化vue對象,保證了每次請求都是獨立的,對於開發者來說,只需要專注於當前業務就可以,不用為服務端渲染開發更多的邏輯程式碼。 renderer生成完成之後,都存在兩個接口,分別是renderToString和renderToStream,一個是一次性將頁面渲染成字串文件,另外一個是串流渲染,適用於支援流的web伺服器,可以是請求服務的速度更快。

第二部分從零開始建立

1、前言

#上一節我們大致講了為什麼需要使用vue後端渲染,以及vue後端渲染的基本原理,這節內容我們將從零開始搭建屬於自己的vue後端渲染腳手架,當然不能不參考官方頁面響應的實例vue-hackernews-2.0,從零開始搭建項目,源碼在將在下節與大家共享。

2、前期准备

基本环境要求:node版本6.10.1以上,npm版本3.10.10以上,本机环境是这样的,建议升级到官方最新版本。

使用的技术栈:

1、vue 2.4.2
2、vuex 2.3.1
3、vue-router 2.7.0
4、vue-server-renderer 2.4.2
5、express 4.15.4
6、axios 0.16.2
7、qs 6.5.0
8、q https://github.com/kriskowal/q.git
9、webpack 3.5.0
10、mockjs 1.0.1-beta3
11、babel 相关插件

以上是主要是用的技术栈,在构建过程中会是用相应的插件依赖包来配合进行压缩打包,以下是npm init后package.json文件所要添加的依赖包。

"dependencies": {
 "axios": "^0.16.2",
 "es6-promise": "^4.1.1",
 "express": "^4.15.4",
 "lodash": "^4.17.4",
 "q": "git+https://github.com/kriskowal/q.git",
 "qs": "^6.5.0",
 "vue": "^2.4.2",
 "vue-router": "^2.7.0",
 "vue-server-renderer": "^2.4.2",
 "vuex": "^2.3.1"
 },
 "devDependencies": {
 "autoprefixer": "^7.1.2",
 "babel-core": "^6.25.0",
 "babel-loader": "^7.1.1",
 "babel-plugin-syntax-dynamic-import": "^6.18.0",
 "babel-plugin-transform-runtime": "^6.22.0",
 "babel-preset-env": "^1.6.0",
 "babel-preset-stage-2": "^6.22.0",
 "compression": "^1.7.1",
 "cross-env": "^5.0.5",
 "css-loader": "^0.28.4",
 "extract-text-webpack-plugin": "^3.0.0",
 "file-loader": "^0.11.2",
 "friendly-errors-webpack-plugin": "^1.6.1",
 "glob": "^7.1.2",
 "less": "^2.7.2",
 "less-loader": "^2.2.3",
 "lru-cache": "^4.1.1",
 "mockjs": "^1.0.1-beta3",
 "style-loader": "^0.19.0",
 "sw-precache-webpack-plugin": "^0.11.4",
 "url-loader": "^0.5.9",
 "vue-loader": "^13.0.4",
 "vue-style-loader": "^3.0.3",
 "vue-template-compiler": "^2.4.2",
 "vuex-router-sync": "^4.2.0",
 "webpack": "^3.5.0",
 "webpack-dev-middleware": "^1.12.0",
 "webpack-hot-middleware": "^2.18.2",
 "webpack-merge": "^4.1.0",
 "webpack-node-externals": "^1.6.0"
 }
登入後複製

3、项目主目录搭建

基本目录结构如下:

├── LICENSE
├── README.md
├── build
│ ├── setup-dev-server.js
│ ├── vue-loader.config.js
│ ├── webpack.base.config.js
│ ├── webpack.client.config.js
│ └── webpack.server.config.js
├── log
│ ├── err.log
│ └── out.log
├── package.json
├── pmlog.json
├── server.js
└── src
 ├── App.vue
 ├── app.js
 ├── assets
 │ ├── images
 │ ├── style
 │ │ └── css.less
 │ └── views
 │  └── index.css
 ├── components
 │ ├── Banner.vue
 │ ├── BottomNav.vue
 │ ├── FloorOne.vue
 │ └── Header.vue
 ├── entry-client.js
 ├── entry-server.js
 ├── index.template.html
 ├── public
 │ ├── conf.js
 │ └── utils
 │  ├── api.js
 │  └── confUtils.js
 ├── router
 │ └── index.js
 ├── static
 │ ├── img
 │ │ └── favicon.ico
 │ └── js
 │  └── flexible.js
 ├── store
 │ ├── actions.js
 │ ├── getters.js
 │ ├── index.js
 │ ├── modules
 │ │ └── Home.js
 │ ├── mutationtypes.js
 │ └── state.js
 └── views
  └── index
   ├── conf.js
   ├── index.vue
   ├── mock.js
   └── service.js
登入後複製

文件目录基本介绍:

  1. views文件夹下分模块文件,模块文件下下又分模块本身的.vue文件(模版文件),index.js文件(后台数据交互文件),mock.js(本模块的mock假数据),conf.js(配置本模块一些参数,请求路径,模块名称等信息)

  2. components 公共组件文件夹

  3. router 主要存放前端路由配置文件,写法规范按照vue-router官方例子即可。

  4. store 主要是存放共享状态文件,里面包含action.js,getter.js,mutationtype.js等,后期会根据模块再细分这些。

  5. public 主要存放公共组件代码和项目使用的公共文件代码,例如后期我们将axios封装成公共的api库文件等等

  6. static文件夹代表静态文件,不会被webpack打包的

  7. app.js 是项目入口文件

  8. App.vue 是项目入口文件

  9. entry-client和entry-server分别是客户端入口文件和服务端的入口文件

  10. index.template.html是整个项目的模版文件

开始编写app.js项目入口代码

使用vue开发项目入口文件一般都会如下写法:

import Vue from &#39;vue&#39;;
import App from &#39;./index.vue&#39;;
import router from &#39;./router&#39;
import store from &#39;./store&#39;;

new Vue({
 el: &#39;#app&#39;,
 store,
 router,
 render: (h) => h(App)
});
登入後複製

这种写法是程序共享一个vue实例,但是在后端渲染中很容易导致交叉请求状态污染,导致数据流被污染了。

所以,避免状态单例,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例,同样router和store入口文件也需要重新创建一个实例。

为了配合webpack动态加载路由配置,这里会改写常规路由引入写法,这样可以根据路由路径来判断加载相应的组件代码:

import Home from &#39;../views/index/index.vue&#39;
// 改写成
component: () => (&#39;../views/index/index.vue&#39;)
登入後複製

以下是路由的基本写法router,对外会抛出一个createRouter方法来创建一个新的路由实例:

import Vue from &#39;vue&#39;
import Router from &#39;vue-router&#39;;
Vue.use(Router)
export function createRouter() {
 return new Router({
  mode: &#39;history&#39;,
  routes: [{
   name:&#39;Home&#39;,
   path: &#39;/&#39;,
   component: () =>
    import (&#39;../views/index/index.vue&#39;)
  }]
 })
}
登入後複製

以下是store状态管理的基本写法,对外暴露了一个createStore方法,方便每次访问创建一个新的实例:

// store.js
import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
import * as actions from &#39;./actions&#39;
import getters from &#39;./getters&#39;
import modules from &#39;./modules/index&#39;
Vue.use(Vuex)
export function createStore() {
 return new Vuex.Store({
 actions,
 getters,
 modules,
 strict: false
 })
}
登入後複製

结合写好的router和store入口文件代码来编写整个项目的入口文件app.js代码内容,同样最终也会对外暴露一个createApp方法,在每次创建app的时候保证router,store,app都是新创建的实例,这里还引入了一个vue路由插件vuex-router-sync,主要作用是同步路由状态(route state)到 store,以下是app.js完整代码:

import Vue from &#39;vue&#39;
import App from &#39;./App.vue&#39;
import { createRouter } from &#39;./router&#39;
import { createStore } from &#39;./store&#39;
import { sync } from &#39;vuex-router-sync&#39;
require(&#39;./assets/style/css.less&#39;);
export function createApp () {
 // 创建 router 和 store 实例
 const router = createRouter()
 const store = createStore()
 // 同步路由状态(route state)到 store
 sync(store, router)
 // 创建应用程序实例,将 router 和 store 注入
 const app = new Vue({
 router,
 store,
 render: h => h(App)
 })
 // 暴露 app, router 和 store。
 return { app, router, store }
}
登入後複製

entry-client.js代码编写:

首页引入从app文件中暴露出来的createApp方法,在每次调用客户端的时候,重新创建一个新的app,router,store,部分代码如下:

import { createApp } from &#39;./app&#39;
const { app, router, store } = createApp()
登入後複製

这里我们会使用到onReady方法,此方法通常用于等待异步的导航钩子完成,比如在进行服务端渲染的时候,例子代码如下:

import { createApp } from &#39;./app&#39;
const { app, router, store } = createApp()
router.onReady(() => {
 app.$mount('#app')
})
登入後複製

我们会调用一个新方法beforeResolve,只有在router2.5.0以上的版本才会有的方法,注册一个类似于全局路由保护router.beforeEach(),除了在导航确认之后,在所有其他保护和异步组件已解决之后调用。基本写法如下:

router.beforeResolve((to, from, next) => {
 // to 和 from 都是 路由信息对象
 // 返回目标位置或是当前路由匹配的组件数组(是数组的定义/构造类,不是实例)。通常在服务端渲染的数据预加载时时候。
 const matched = router.getMatchedComponents(to)
 const prevMatched = router.getMatchedComponents(from)
})
登入後複製

服务端把要给客户端的 state 放在了 window. INITIAL_STATE 这个全局变量上面。前后端的 HTML 结构应该是一致的。然后要把 store 的状态树写入一个全局变量( INITIAL_STATE ),这样客户端初始化 render 的时候能够校验服务器生成的 HTML 结构,并且同步到初始化状态,然后整个页面被客户端接管。基本代码如下:

// 将服务端渲染时候的状态写入vuex中
if (window.__INITIAL_STATE__) {
 store.replaceState(window.__INITIAL_STATE__)
}
登入後複製

接下来贴出来完整的客户端代码,这里的Q也可以不用引入,直接使用babel就能编译es6自带的Promise,因为本人使用习惯了,这里可以根据自身的需求是否安装:

import { createApp } from &#39;./app&#39;
import Q from &#39;q&#39;
import Vue from &#39;vue&#39;

Vue.mixin({
 beforeRouteUpdate (to, from, next) {
 const { asyncData } = this.$options
 if (asyncData) {
  asyncData({
  store: this.$store,
  route: to
  }).then(next).catch(next)
 } else {
  next()
 }
 }
})
const { app, router, store } = createApp()

// 将服务端渲染时候的状态写入vuex中
if (window.__INITIAL_STATE__) {
 store.replaceState(window.__INITIAL_STATE__)
}

router.onReady(() => {
 router.beforeResolve((to, from, next) => {
  const matched = router.getMatchedComponents(to)
  const prevMatched = router.getMatchedComponents(from)
  // 我们只关心之前没有渲染的组件
  // 所以我们对比它们,找出两个匹配列表的差异组件
  let diffed = false
  const activated = matched.filter((c, i) => {
  return diffed || (diffed = (prevMatched[i] !== c))
  })
  if (!activated.length) {
  return next()
  }
  // 这里如果有加载指示器(loading indicator),就触发
  Q.all(activated.map(c => {
  if (c.asyncData) {
   return c.asyncData({ store, route: to })
  }
  })).then(() => {
  // 停止加载指示器(loading indicator)
  next()
  }).catch(next)
 })
 app.$mount(&#39;#app&#39;)
})
登入後複製

entry-server.js代码编写:

基本编写和客户端的差不多,因为这是服务端渲染,涉及到与后端数据交互定义的问题,我们需要在这里定义好各组件与后端交互使用的方法名称,这样方便在组件内部直接使用,这里根我们常规在组件直接使用ajax获取数据有些不一样,代码片段如下:

//直接定义组件内部asyncData方法来触发相应的ajax获取数据
if (Component.asyncData) {
 return Component.asyncData({
 store,
 route: router.currentRoute
 })
}
登入後複製

以下是完整的服务端代码:

import { createApp } from &#39;./app&#39;
import Q from &#39;q&#39;
export default context => {
 return new Q.Promise((resolve, reject) => {
 const { app, router, store } = createApp()
 router.push(context.url)
 router.onReady(() => {
  const matchedComponents = router.getMatchedComponents()
  if (!matchedComponents.length) {
  return reject({ code: 404 })
  }
  // 对所有匹配的路由组件调用 `asyncData()`
  Q.all(matchedComponents.map(Component => {
  if (Component.asyncData) {
   return Component.asyncData({
   store,
   route: router.currentRoute
   })
  }
  })).then(() => {
  // 在所有预取钩子(preFetch hook) resolve 后,
  // 我们的 store 现在已经填充入渲染应用程序所需的状态。
  // 当我们将状态附加到上下文,
  // 并且 `template` 选项用于 renderer 时,
  // 状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。
  context.state = store.state
  resolve(app)
  }).catch(reject)
 }, reject)
 })
}
登入後複製

4、脚手架其他目录介绍:

到这里src下面主要的几个文件代码已经编写完成,接下里介绍下整个项目的目录结构如下:

主要几个文件介绍如下:

  1. build 主要存放webpack打包配置文件

  2. dist webpack打包后生成的目录

  3. log 使用pm2监控进程存放的日志文件目录

  4. server.js node服务器启动文件

  5. pmlog.json pm2配置文件

server.js入口文件编写

我们还需要编写在服务端启动服务的代码server.js,我们会使用到部分node原生提供的api,片段代码如下:

const Vue = require(&#39;vue&#39;)
const express = require(&#39;express&#39;)
const path = require(&#39;path&#39;)
const LRU = require(&#39;lru-cache&#39;)
const { createBundleRenderer } = require(&#39;vue-server-renderer&#39;)
const fs = require(&#39;fs&#39;)
const net = require(&#39;net&#39;)
登入後複製

大致思路是,引入前端模版页面index.template.html,使用express启动服务,引入webpack打包项目代码的dist文件,引入缓存模块(这里不做深入介绍,后期会单独详细介绍),判断端口是否被占用,自动启动其他接口服务。

引入前端模版文件并且设置环境变量为production,片段代码如下:

const template = fs.readFileSync(&#39;./src/index.template.html&#39;, &#39;utf-8&#39;)
const isProd = process.env.NODE_ENV === &#39;production&#39;
登入後複製

vue-server-renderer插件的具体使用,通过读取dist文件夹下的目录文件,来创建createBundleRenderer函数,并且使用LRU来设置缓存的时间,通过判断是生产环境还是开发环境,调用不同的方法,代码片段如下:

const resolve = file => path.resolve(__dirname, file)
function createRenderer (bundle, options) {
 return createBundleRenderer(bundle, Object.assign(options, {
 template,
 cache: LRU({
  max: 1000,
  maxAge: 1000 * 60 * 15
 }),
 basedir: resolve(&#39;./dist&#39;),
 runInNewContext: false
 }))
}
let renderer;
let readyPromise
if (isProd) {
 const bundle = require(&#39;./dist/vue-ssr-server-bundle.json&#39;)
 const clientManifest = require(&#39;./dist/vue-ssr-client-manifest.json&#39;)
 renderer = createRenderer(bundle, {
 clientManifest
 })
} else {
 readyPromise = require(&#39;./build/setup-dev-server&#39;)(server, (bundle, options) => {
 renderer = createRenderer(bundle, options)
 })
}
登入後複製

使用express启动服务,代码片段如下:

const server = express();

//定义在启动服务钱先判断中间件中的缓存是否过期,是否直接调用dist文件。
const serve = (path, cache) => express.static(resolve(path), {
 maxAge: cache && isProd ? 1000 * 60 * 60 * 24 * 30 : 0
})
server.use(&#39;/dist&#39;, serve(&#39;./dist&#39;, true))
server.get(&#39;*&#39;, (req, res) => {
 const context = {
 title: &#39;hello&#39;,
 url: req.url
 }
 renderer.renderToString(context, (err, html) => {
 if (err) {
  res.status(500).end(&#39;Internal Server Error&#39;)
  return
 }
 res.end(html)
 })
})
登入後複製

判断端口是否被占用,片段代码如下:

function probe(port, callback) {
 let servers = net.createServer().listen(port)
 let calledOnce = false
 let timeoutRef = setTimeout(function() {
  calledOnce = true
  callback(false, port)
 }, 2000)
 timeoutRef.unref()
 let connected = false
 servers.on(&#39;listening&#39;, function() {
  clearTimeout(timeoutRef)

  if (servers)
   servers.close()

  if (!calledOnce) {
   calledOnce = true
   callback(true, port)
  }
 })
 servers.on(&#39;error&#39;, function(err) {
  clearTimeout(timeoutRef)

  let result = true
  if (err.code === &#39;EADDRINUSE&#39;)
   result = false

  if (!calledOnce) {
   calledOnce = true
   callback(result, port)
  }
 })
}
const checkPortPromise = new Promise((resolve) => {
 (function serverport(_port) {
  let pt = _port || 8080;
  probe(pt, function(bl, _pt) {
   // 端口被占用 bl 返回false
   // _pt:传入的端口号
   if (bl === true) {
    // console.log("\n Static file server running at" + "\n\n=> http://localhost:" + _pt + &#39;\n&#39;);
    resolve(_pt);
   } else {
    serverport(_pt + 1)
   }
  })
 })()

})
checkPortPromise.then(data => {
 uri = &#39;http://localhost:&#39; + data;
 console.log(&#39;启动服务路径&#39;+uri)
 server.listen(data);
});
登入後複製

到这里,基本的代码已经编写完成,webpack打包配置文件基本和官方保持不变,接下来可以尝试启动本地的项目服务,这里简要的使用网易严选首页作为demo示例,结果如下:

第三部分 mockjs和axios配合使用

1、前言

上一节大致介绍了服务端和客户端入口文件代码内容,现在已经可以正常运行你的后端渲染脚手架了,这一节,跟大家分享下如何使用axios做ajax请求,如何使用mockjs做本地假数据,跑通本地基本逻辑,为以后前后端连调做准备。

2、前期准备

需要用npm安装axios,mockjs依赖包,由于mockjs只是代码开发的辅助工具,所以安装的时候我会加--save-dev来区分,具体可以根据自己的需求来定,当然,如果有mock服务平台的话,可以直接走mock平台造假数据,本地直接访问mock平台的接口,例如可以使用阿里的Rap平台管理工具生成。

npm install axios --save
npm install mockjs --save-dev
登入後複製

3、简要介绍axios

其他请求方式,代码示例如下:

axios.request(config);
axios.get(url[,config]);
axios.delete(url[,config]);
axios.head(url[,config]);
axios.post(url[,data[,config]]);
axios.put(url[,data[,config]])
axios.patch(url[,data[,config]])
登入後複製

具体详细可以点击查看axios基本使用介绍

api.js完整代码如下:

import axios from &#39;axios&#39;
import qs from &#39;qs&#39;
import Q from &#39;q&#39;
/**
 * 兼容 不支持promise 的低版本浏览器
 */
require(&#39;es6-promise&#39;).polyfill();
import C from &#39;../conf&#39;

axios.defaults.headers.post[&#39;Content-Type&#39;] = &#39;application/x-www-form-urlencoded; charset=UTF-8&#39;
axios.defaults.withCredentials = true

function ajax(url, type, options) {

 return Q.Promise((resolve, reject) => {
 axios({
  method: type,
  url: C.HOST + url,
  params: type === &#39;get&#39; ? options : null,
  data: type !== &#39;get&#39; ? qs.stringify(options) : null
  })
  .then((result) => {
  if (result && result.status === 401) {
   // location.href = &#39;/views/401.html&#39;
  }
  if (result && result.status === 200) {
   if (result.data.code === 200) {
   resolve(result.data.data);
   } else if (result.data.code === 401) {
   reject({
    nopms: true,
    msg: result.data.msg
   });
   } else {
   reject({
    error: true,
    msg: result.data.msg
   });
   }
  } else {
   reject({
   errno: result.errno,
   msg: result.msg
   });
  }
  })
  .catch(function(error) {
  console.log(error, url);
  });
 })
}

const config = {
 get(url, options) {
 const _self = this;
 return Q.Promise((resolve, reject) => {
  ajax(url, &#39;get&#39;, options)
  .then((data) => {
   resolve(data);
  }, (error) => {
   reject(error);
  });
 })
 },

 post(url, options) {
 const _self = this;
 return Q.Promise((resolve, reject) => {
  ajax(url, &#39;post&#39;, options)
  .then((data) => {
   resolve(data);
  }, (error) => {
   reject(error);
  });
 })
 },

 put(url, options) {
 const _self = this;
 return Q.Promise((resolve, reject) => {
  ajax(url, &#39;put&#39;, options)
  .then((data) => {
   resolve(data);
  }, (error) => {
   reject(error);
  });
 })
 },

 delete(url, options) {
 const _self = this;
 return Q.Promise((resolve, reject) => {
  ajax(url, &#39;delete&#39;, options)
  .then((data) => {
   resolve(data);
  }, (error) => {
   reject(error);
  });
 })
 },

 jsonp(url, options) {
 const _self = this;
 return Q.Promise((resolve, reject) => {
  ajax(url, &#39;jsonp&#39;, options)
  .then((data) => {
   resolve(data);
  }, (error) => {
   reject(error);
  });
 })
 }
};

export default config;
登入後複製

mockjs项目基本配置如下:

1、在public下新建conf.js全局定义请求url地址,代码如下:

module.exports = {
 HOST: "http://www.xxx.com",
 DEBUGMOCK: true
};
登入後複製

2、在views/index根目录下新建conf.js,定义组件mock的请求路径,并且定义是否开始单个组件使用mock数据还是线上接口数据,代码如下:

const PAGEMOCK = true;
const MODULECONF = {
 index: {
 NAME: &#39;首页&#39;,
 MOCK: true,
 API: {
  GET: &#39;/api/home&#39;,
 }
 }
};
登入後複製

3、在组件内部定义mockjs来编写mock假数据,代码如下:

import Mock from &#39;mockjs&#39;;
const mData = {
 index: {
 API: {
  GET: {
  "code": 200,
  "data": {
   "pin": &#39;wangqi&#39;,
   "name": &#39;王奇&#39;
  }
  }
 }
 }
}
登入後複製

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在微信小程序中如何实现流程进度样式?

在vue中使用vue-cli如何搭建helloWorld

layui中有关取值传值方面的问题

详细解答vue的变化对组件有什么影响?

在vue-scroller中如何标记记录滚动位置

以上是使用vue-ssr如何實現服務端渲染的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1668
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1273
29
C# 教程
1256
24
vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

vue怎麼給按鈕添加函數 vue怎麼給按鈕添加函數 Apr 08, 2025 am 08:51 AM

可以通過以下步驟為 Vue 按鈕添加函數:將 HTML 模板中的按鈕綁定到一個方法。在 Vue 實例中定義該方法並編寫函數邏輯。

vue中的watch怎麼用 vue中的watch怎麼用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 選項允許開發者監聽特定數據的變化。當數據發生變化時,watch 會觸發一個回調函數,用於執行更新視圖或其他任務。其配置選項包括 immediate,用於指定是否立即執行回調,以及 deep,用於指定是否遞歸監聽對像或數組的更改。

vue返回上一頁的方法 vue返回上一頁的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一頁有四種方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 組件window.history.back(),方法選擇取決於場景。

React與Vue:Netflix使用哪個框架? React與Vue:Netflix使用哪個框架? Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVuedIrectly.1)TeamSperience:selectBasedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects:reactforforforproproject,reactforforforcompleplexones.3)cocatizationneedneeds:reactoffipicatizationneedneedneedneedneedneeds:reactoffersizationneedneedneedneedneeds:reactoffersizatization needefersmoreflexibleise.4)

vue多頁面開發是啥意思 vue多頁面開發是啥意思 Apr 07, 2025 pm 11:57 PM

Vue 多頁面開發是一種使用 Vue.js 框架構建應用程序的方法,其中應用程序被劃分為獨立的頁面:代碼維護性:將應用程序拆分為多個頁面可以使代碼更易於管理和維護。模塊化:每個頁面都可以作為獨立的模塊,便於重用和替換。路由簡單:頁面之間的導航可以通過簡單的路由配置來管理。 SEO 優化:每個頁面都有自己的 URL,這有助於搜索引擎優化。

vue遍歷怎麼用 vue遍歷怎麼用 Apr 07, 2025 pm 11:48 PM

Vue.js 遍歷數組和對像有三種常見方法:v-for 指令用於遍歷每個元素並渲染模板;v-bind 指令可與 v-for 一起使用,為每個元素動態設置屬性值;.map 方法可將數組元素轉換為新數組。

vue.js怎麼引用js文件 vue.js怎麼引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三種:直接使用 &lt;script&gt; 標籤指定路徑;利用 mounted() 生命週期鉤子動態導入;通過 Vuex 狀態管理庫進行導入。

See all articles