亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

15分鐘學(xué)會vue項目改造成SSR(小白教程)

 更新時間:2019年12月17日 10:35:28   作者:左右同學(xué)  
這篇文章主要介紹了15分鐘學(xué)會vue項目改造成SSR(小白教程),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

15分鐘學(xué)會vue項目改造成SSR

Ps:網(wǎng)上看了好多服務(wù)器渲染的例子,基本都是從0開始的,用Nuxt或者vue官網(wǎng)推薦的ssr方案(vue-server-renderer),但是我們在開發(fā)過程中基本上是已經(jīng)有了現(xiàn)有的項目了,我們所要做的是對現(xiàn)有項目的SSR改造。那么這里,跟我一起對一個vue-cil2.0生成的項目進行SSR改造

關(guān)于這篇文章的案例源代碼我放在我的github上面,有興趣的同學(xué),也可以去我的github查看我之前寫的博客。博客

一、改造技術(shù)的分析對比。

一般來說,我們做seo有兩種方式:

1、預(yù)渲染

我在性能優(yōu)化的博客中說過,預(yù)渲染的問題,預(yù)渲染是一個方案,使用爬蟲技術(shù)。由于我們打包過后的都是一些js文件,使用一些技術(shù)(puppeteer)可以爬取到項目在chrome瀏覽器展示的頁面,然后把它寫入js,和打包文件一起。

類似prerender-spa-plugin 。最大的特點就是,所有獲取的數(shù)據(jù)都是靜態(tài)的,比如說你的頁面首頁有新聞,是通過接口獲取的,當你在2019-11-30打包之后,不管用戶在2020年也是看到的2019-11-30的新聞,當然的爬蟲爬到的也是。

如果你只需要改善少數(shù)頁面(例如 /, /about, /contact 等)的 SEO,那么你可能需要預(yù)渲染

2、服務(wù)端渲染

服務(wù)端渲染是將完整的 html 輸出到客戶端,又被認為是‘同構(gòu)'或‘通用',如果你的項目有大量的detail頁面,相互特別頻繁,建議選擇服務(wù)端渲染。

**服務(wù)端渲染除了SEO還有很多時候用作首屏優(yōu)化,加快首屏速度,提高用戶體驗。**但是對服務(wù)器有要求,網(wǎng)絡(luò)傳輸數(shù)據(jù)量大,占用部分服務(wù)器運算資源。

由于三大框架的興起,SPA項目到處都是,所以涌現(xiàn)了一批nuxt.js、next.js這些服務(wù)器渲染的框架。但是這些框架構(gòu)建出來的項目可能文件夾和我們現(xiàn)有的項目很大不一樣,所以本文章主要是用vue-server-renderer來對現(xiàn)有項目進行改造,而不是去用框架。

ps:(劃重點)單頁面項目的ssr改造的原理:

vue項目是通過虛擬 DOM來掛載到html的,所以對spa項目,爬蟲才會只看到初始結(jié)構(gòu)。虛擬 DOM,最終要通過一定的方法將其轉(zhuǎn)換為真實 DOM。虛擬 DOM 也就是 JS 對象,整個服務(wù)端的渲染流程就是通過虛擬 DOM 的編譯成完整的html來完成的。

我們通過服務(wù)端渲染解析虛擬 DOM成html之后,你會發(fā)現(xiàn)頁面的事件,都沒法觸發(fā)。那是因為服務(wù)端渲染vue-server-renderer插件并沒有做這方面的處理,所以我們需要客戶端再渲染一遍,簡稱同構(gòu)。所以Vue服務(wù)端渲染其實是渲染了兩遍。下面給出一個官方的圖:

在這里插入圖片描述

二、改造前后目錄文件對比

在這里插入圖片描述

黃線部分是改造后新增的文件,怎么樣,是不是覺得差別不大,總體架構(gòu)上只有6個文件的差別。(#.#) 我們來理一理這些新增的文件。

  • server.dev.conf.js 本地調(diào)試和熱更新需要的配置文件
  • webpack.client.conf.js 客戶端打包配置文件,ssr打包是生成分為客戶端和服務(wù)端的兩部分打包文件
  • webpack.server.conf.js 服務(wù)端打包配置文件,ssr打包是生成分為客戶端和服務(wù)端的兩部分打包文件
  • entry-client.js 客戶端入口文件。spa的入口是main.js,ssr就分為兩個入口(服務(wù)端和客戶端)
  • entry-server.js 服務(wù)端入口文件。spa的入口是main.js,ssr就分為兩個入口(服務(wù)端和客戶端)
  • index.template.html 模板文件,因為服務(wù)端渲染是通過服務(wù)器把頁面丟出來,所以我們需要一個模板,作為頁面初始載體,然后往里面添加內(nèi)容。
  • server.js 啟動文件,服務(wù)端渲染我們需要啟動一個node服務(wù)器,主要配置在這個文件里面。

三、webpack添加客戶端與服務(wù)端配置

1.webpack客戶端配置

const webpack = require('webpack')
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.conf.js')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

module.exports = merge(baseConfig, {
 entry: './src/entry-client.js',
 plugins: [
  new webpack.optimize.CommonsChunkPlugin({
   name: "manifest",
   minChunks: Infinity
  }),
  // 此插件在輸出目錄中
  // 生成 `vue-ssr-client-manifest.json`。
  new VueSSRClientPlugin(),
  new HtmlWebpackPlugin({
   template: path.resolve(__dirname, './../src/index.template.html'),
   filename: 'index.template.html'
  })
 ]
})

這里面和spa項目有兩點不同,第一是入口變了,變?yōu)榱薳ntry-client.js。第二是VueSSRClientPlugin,這個是生成一個vue-ssr-client-manifest.json客戶端入口文件。

2.webpack服務(wù)端配置

const merge = require('webpack-merge')
const nodeExternals = require('webpack-node-externals')
const baseConfig = require('./webpack.base.conf.js')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')

module.exports = merge(baseConfig, {
 // 將 entry 指向應(yīng)用程序的 server entry 文件
 entry: './src/entry-server.js',

 // 這允許 webpack 以 Node 適用方式(Node-appropriate fashion)處理動態(tài)導(dǎo)入(dynamic import),
 // 并且還會在編譯 Vue 組件時,
 // 告知 `vue-loader` 輸送面向服務(wù)器代碼(server-oriented code)。
 target: 'node',

 // 對 bundle renderer 提供 source map 支持
 devtool: 'source-map',

 // 此處告知 server bundle 使用 Node 風(fēng)格導(dǎo)出模塊(Node-style exports)
 output: {
  libraryTarget: 'commonjs2'
 },
 externals: nodeExternals({
  // 不要外置化 webpack 需要處理的依賴模塊。
  // 你可以在這里添加更多的文件類型。例如,未處理 *.vue 原始文件,
  // 你還應(yīng)該將修改 `global`(例如 polyfill)的依賴模塊列入白名單
  whitelist: /\.css$/
 }),

 // 這是將服務(wù)器的整個輸出
 // 構(gòu)建為單個 JSON 文件的插件。
 // 默認文件名為 `vue-ssr-server-bundle.json`
 plugins: [
  new VueSSRServerPlugin()
 ]
})

這段代碼一目了然,第一是是告訴webpack這是要打包node能運行的東西,第二是打包一個服務(wù)端入口vue-ssr-server-bundle.json

四、vue、router、store實例改造

當編寫純客戶端 (client-only) 代碼時,我們習(xí)慣于每次在新的上下文中對代碼進行取值。但是,Node.js 服務(wù)器是一個長期運行的進程。當我們的代碼進入該進程時,它將進行一次取值并留存在內(nèi)存中。這意味著如果創(chuàng)建一個單例對象,它將在每個傳入的請求之間共享。

nodejs是一個運行時,如果只是個單例的話,所有的請求都會共享這個單例,會造成狀態(tài)污染。所以我們需要為每個請求創(chuàng)造一個vue,router,store實例。

第一步修改main.js

// main.js
import Vue from 'vue'
import App from './App.vue'
import { createRouter } from './router'
import { createStore } from './store/store.js'
import { sync } from 'vuex-router-sync'

export function createApp () {
 // 創(chuàng)建 router 實例
 const router = createRouter()
 const store = createStore()

 // 同步路由狀態(tài)(route state)到 store
 sync(store, router)

 const app = new Vue({
  // 注入 router 到根 Vue 實例
  router,
  store,
  render: h => h(App)
 })

 // 返回 app 和 router
 return { app, router, store }
}

看到這個createApp沒,沒錯,它就是我們熟悉的工廠模式。同樣的store和router一樣改造

// router.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)


export let createRouter = () => {
 let route = new Router({
  mode:'history',
  routes: []
 })
 return route
}
// store.js
// store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export function createStore () {
 return new Vuex.Store({
  state: {
  },
  actions: {
  },
  mutations: {
  }
 })
}

到這里,三個實例對象改造完成了。是不是很簡單~

五、數(shù)據(jù)預(yù)取和存儲

服務(wù)器渲染,可以理解為在被訪問的時候,服務(wù)端做預(yù)渲染生成頁面,上面說過,預(yù)渲染的缺點就是,實時數(shù)據(jù)的獲取。所以如果應(yīng)用程序依賴于一些異步數(shù)據(jù),那么在開始渲染過程之前,需要先預(yù)取和解析好這些數(shù)據(jù)。

另一個需要關(guān)注的問題是在客戶端,在掛載 (mount) 到客戶端應(yīng)用程序之前,需要獲取到與服務(wù)器端應(yīng)用程序完全相同的數(shù)據(jù) - 否則,客戶端應(yīng)用程序會因為使用與服務(wù)器端應(yīng)用程序不同的狀態(tài),然后導(dǎo)致混合失敗。這個地方上面提過,叫同構(gòu)(服務(wù)端渲染一遍,客戶端拿到數(shù)據(jù)再渲染一遍)。

因為我們用的vue框架嘛,那當然數(shù)據(jù)存儲選vuex咯。然后我們來理一下總體的流程:

客戶端訪問網(wǎng)站 —> 服務(wù)器獲取動態(tài)數(shù)據(jù),生成頁面,并把數(shù)據(jù)存入vuex中,然后返回html —> 客戶端獲取html(此時已經(jīng)返回了完整的頁面) —> 客戶端獲取到vuex的數(shù)據(jù),并解析到vue里面,然后再一次找到根元素掛載vue,重復(fù)渲染頁面。(同構(gòu)階段)

流程清楚之后,那我們怎么設(shè)定,哪個地方的代碼,被服務(wù)端執(zhí)行,并獲取數(shù)據(jù)存入vuex呢? 我們分為三步:

1.自定義函數(shù)asyncData

官方的例子是定義一個asyncData函數(shù)(這個名字不是唯一的哈,是自己定義的,可以隨便取,不要理解為內(nèi)置的函數(shù)哈),這個函數(shù)寫在路由組件里面。
假設(shè)有一個Item.vue組件(官網(wǎng)的例子)

<!-- Item.vue -->
<template>
 <div>{{ item.title }}</div>
</template>

<script>
export default {
 asyncData ({ store, route }) {
  // 觸發(fā) action 后,會返回 Promise
  return store.dispatch('fetchItem', route.params.id)
 },
 computed: {
  // 從 store 的 state 對象中的獲取 item。
  item () {
   return this.$store.state.items[this.$route.params.id]
  }
 }
}
</script>

2. 服務(wù)端入口entry-server.js配置

到這里,asyncData函數(shù),我們知道它是放在哪里了。接下來,我們有了這個函數(shù),我們服務(wù)器肯定要去讀到這個函數(shù),然后去獲取數(shù)據(jù)吧?我們把目光放到entry-server.js,之前我們提到過,這是服務(wù)端的入口頁面。那我們是不是能夠在這里面處理asyncData呢。下面還是官網(wǎng)的例子:

// entry-server.js
import { createApp } from './app'

export default context => {
 return new 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 })
   }

   // 對所有匹配的路由組件調(diào)用 `asyncData()`
   Promise.all(matchedComponents.map(Component => {
    if (Component.asyncData) {
     return Component.asyncData({
      store,
      route: router.currentRoute
     })
    }
   })).then(() => {
    // 在所有預(yù)取鉤子(preFetch hook) resolve 后,
    // 我們的 store 現(xiàn)在已經(jīng)填充入渲染應(yīng)用程序所需的狀態(tài)。
    // 當我們將狀態(tài)附加到上下文,
    // 并且 `template` 選項用于 renderer 時,
    // 狀態(tài)將自動序列化為 `window.__INITIAL_STATE__`,并注入 HTML。
    context.state = store.state

    resolve(app)
   }).catch(reject)
  }, reject)
 })
}

簡單的讀下這段代碼。首先為什么是返回Promise呢?因為可能是異步路由和組件,我們得保證,服務(wù)器渲染之前,已經(jīng)完全準備就緒了。 然后注意**matchedComponents **它是通過傳入的地址,獲取到和路由匹配到的組件,然后如果存在asyncData,我們就去執(zhí)行它,然后注入到context(渲染上下文,可以在客戶端獲取)里面。

是不是簡單?這一步我們就已經(jīng)從服務(wù)器端取到動態(tài)數(shù)據(jù)了,同時丟到頁面里面了。如果不是為了客戶端數(shù)據(jù)同步,這一步我們已經(jīng)搞完服務(wù)端渲染了~ = =

3.客戶端入口client-server.js配置

搞完服務(wù)器端的配置,該客戶端了,畢竟數(shù)據(jù)要同步嘛。我們來看看客戶端的入口文件代碼:

const { app, router, store } = createApp()

if (window.__INITIAL_STATE__) {
 store.replaceState(window.__INITIAL_STATE__)
}

之前服務(wù)端入口說過,狀態(tài)將自動序列化為 window.__INITIAL_STATE__,并注入 HTML。
所以客戶端我們獲取到了,服務(wù)端已經(jīng)搞好了數(shù)據(jù)了,我們拿過來直接替換現(xiàn)有的vuex就好了。

看到這里,不是已經(jīng)完成啦,完整的流程。但是到此為止了嗎?還沒呢,既然是服務(wù)端渲染,你總要啟動服務(wù)器吧…

Ps: 數(shù)據(jù)預(yù)期,我們剛才講到的只是服務(wù)端預(yù)取,其實還有客戶端預(yù)取。什么是客戶端預(yù)取呢,簡單的理解就是,我們可以在路由鉤子里面,找有當前路由組件沒有asyncData,有的話,就去請求,獲取到數(shù)據(jù)后,填充完之后,再渲染頁面。

六、啟動服務(wù)(server.js)配置

服務(wù)端渲染,服務(wù)端,肯定要一個啟動服務(wù)的文件哈,

const express = require("express");

const fs = require('fs');
let path = require("path");
const server = express()
const { createBundleRenderer } = require('vue-server-renderer')

let renderer

const resolve = file => path.resolve(__dirname, file)
const templatePath = resolve('./src/index.template.html')
function createRenderer (bundle, options) {

 return createBundleRenderer(bundle, Object.assign(options, {
  runInNewContext: false
 }))
}

const template = fs.readFileSync(templatePath, 'utf-8')
const bundle = require('./dist/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
renderer = createRenderer(bundle, {
 template,
 clientManifest
})


server.use(express.static('./dist'))
// 在服務(wù)器處理函數(shù)中……
server.get('*', (req, res) => {
 const context = { url: req.url }
 // 這里無需傳入一個應(yīng)用程序,因為在執(zhí)行 bundle 時已經(jīng)自動創(chuàng)建過。
 renderer.renderToString(context, (err, html) => {
  // 處理異?!?
  res.end(html)
 })
})
server.listen(3001, () => {
  console.log('服務(wù)已開啟')
})

這就是服務(wù)端的啟動代碼了,只需處理獲取幾個打包過后的參數(shù)(template模板和clientManifest),傳入createBundleRenderer函數(shù)。然后通過renderToString,展現(xiàn)給客戶端。

七、熱更新與本地調(diào)試

上面一步是啟動服務(wù),但是我們本地調(diào)試的時候,不可能每次build之后,再啟動,然后再修改,再build吧?那也太麻煩了。所以我們借助webpack搞一個熱更新。這里在build里面添加一個文件
server.dev.conf.js

//server.dev.conf.js

const fs = require('fs')
const path = require('path')
const MFS = require('memory-fs')
const webpack = require('webpack')
const chokidar = require('chokidar')
const clientConfig = require('./webpack.client.conf.js')
const serverConfig = require('./webpack.server.conf.js')

const readFile = (fs, file) => {
 try {
  return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8')
 } catch (e) {}
}

module.exports = function setupDevServer (app, templatePath, cb) {
 let bundle
 let template
 let clientManifest

 let ready
 const readyPromise = new Promise(r => { ready = r })
 const update = () => {
  if (bundle && clientManifest) {
   ready()
   cb(bundle, {
    template,
    clientManifest
   })
  }
 }

 // read template from disk and watch
 template = fs.readFileSync(templatePath, 'utf-8')
 chokidar.watch(templatePath).on('change', () => {
  template = fs.readFileSync(templatePath, 'utf-8')
  console.log('index.html template updated.')
  update()
 })

 // modify client config to work with hot middleware
 clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app]
 clientConfig.output.filename = '[name].js'
 clientConfig.plugins.push(
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoEmitOnErrorsPlugin()
 )

 // dev middleware
 const clientCompiler = webpack(clientConfig)
 const devMiddleware = require('webpack-dev-middleware')(clientCompiler, {
  publicPath: clientConfig.output.publicPath,
  noInfo: true
 })
 app.use(devMiddleware)
 clientCompiler.plugin('done', stats => {
  stats = stats.toJson()
  stats.errors.forEach(err => console.error(err))
  stats.warnings.forEach(err => console.warn(err))
  if (stats.errors.length) return
  clientManifest = JSON.parse(readFile(
   devMiddleware.fileSystem,
   'vue-ssr-client-manifest.json'
  ))
  update()
 })

 // hot middleware
 app.use(require('webpack-hot-middleware')(clientCompiler, { heartbeat: 5000 }))

 // watch and update server renderer
 const serverCompiler = webpack(serverConfig)
 const mfs = new MFS()
 serverCompiler.outputFileSystem = mfs
 serverCompiler.watch({}, (err, stats) => {
  if (err) throw err
  stats = stats.toJson()
  if (stats.errors.length) return

  // read bundle generated by vue-ssr-webpack-plugin
  bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))
  update()
 })

 return readyPromise
}

這個代碼基本上是從官方文檔copy下來的,寫的挺好的 哈哈。

怎么理解這段代碼呢,這個代碼封裝了一個promise,因為代碼更新后重新打包需要時間,所以我們在renderToString之前,需要等待一段處理的時間。這個代碼對3部分進行了監(jiān)控,template.html、vue業(yè)務(wù)代碼、客戶端配置代碼。檢測到有改動之后,就重新打包獲取,然后返回。這里就是熱更新部分代碼,當然我們還要改動server.js部分代碼,畢竟要處理開發(fā)模式和生成模式的不同。

//server.js
const express = require("express");

const fs = require('fs');
let path = require("path");
const server = express()
const { createBundleRenderer } = require('vue-server-renderer')
const isProd = process.env.NODE_ENV === 'production'
let renderer
let readyPromise
const resolve = file => path.resolve(__dirname, file)
const templatePath = resolve('./src/index.template.html')
function createRenderer (bundle, options) {
 return createBundleRenderer(bundle, Object.assign(options, {
  runInNewContext: false
 }))
}

if(isProd){
 const template = fs.readFileSync(templatePath, 'utf-8')
 const bundle = require('./dist/vue-ssr-server-bundle.json')
 const clientManifest = require('./dist/vue-ssr-client-manifest.json')
 renderer = createRenderer(bundle, {
  template,
  clientManifest
 })

}else{
 readyPromise = require('./build/server.dev.conf.js')(
  server,
  templatePath,
  (bundle, options) => {
   renderer = createRenderer(bundle, options)
  }
 )
}
server.use(express.static('./dist'))
// 在服務(wù)器處理函數(shù)中……
server.get('*', (req, res) => {
 const context = { url: req.url }
 // 這里無需傳入一個應(yīng)用程序,因為在執(zhí)行 bundle 時已經(jīng)自動創(chuàng)建過。
 // 現(xiàn)在我們的服務(wù)器與應(yīng)用程序已經(jīng)解耦!
 if(isProd){
  renderer.renderToString(context, (err, html) => {
   // 處理異常……
   res.end(html)
  })
 }else{
  readyPromise.then(()=>{
   renderer.renderToString(context, (err, html) => {
    // 處理異?!?
    res.end(html)
   })
  })
 }
})
server.listen(3001, () => {
  console.log('服務(wù)已開啟')
})

從server.js的代碼改動,我們可以看到,server進行了是否為生產(chǎn)環(huán)境的判斷,如果是測試環(huán)境,就取運行server.dev.conf.js,獲得返回的promise,然后再renderToString之前,把renderToString加入到promise鏈式調(diào)用里面,這樣,熱更新就完成了,每次調(diào)用路由的時候,都會去獲取到最新的頁面。

到這里所有的ssr改造已經(jīng)完成了,當然我們還能優(yōu)化,下面給出幾個點,自己思考哈:

  • 服務(wù)器緩存,既然是node服務(wù)器,我們當然可以做服務(wù)器緩存拉。
  • 流式渲染 (Streaming) 用 renderToStream 替代 renderToString;當 renderer 遍歷虛擬 DOM 樹 (virtual DOM tree) 時,會盡快發(fā)送數(shù)據(jù)。這意味著我們可以盡快獲得"第一個 chunk",并開始更快地將其發(fā)送給客戶端

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue框架和react框架的區(qū)別以及各自的應(yīng)用場景使用

    vue框架和react框架的區(qū)別以及各自的應(yīng)用場景使用

    這篇文章主要介紹了vue框架和react框架的區(qū)別以及各自的應(yīng)用場景使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Vue實現(xiàn)雙向綁定的原理以及響應(yīng)式數(shù)據(jù)的方法

    Vue實現(xiàn)雙向綁定的原理以及響應(yīng)式數(shù)據(jù)的方法

    這篇文章主要介紹了Vue實現(xiàn)雙向綁定的原理以及響應(yīng)式數(shù)據(jù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • 基于vue封裝一個帶眼睛的密碼子組件

    基于vue封裝一個帶眼睛的密碼子組件

    這篇文章給大家介紹了基于vue封裝一個帶眼睛的密碼子組件的方法,文章中有詳細的代碼講解,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-09-09
  • vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作

    vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作

    這篇文章主要介紹了vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • vue如何實現(xiàn)接口統(tǒng)一管理

    vue如何實現(xiàn)接口統(tǒng)一管理

    這篇文章主要介紹了vue如何實現(xiàn)接口統(tǒng)一管理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Vue+axios 實現(xiàn)http攔截及路由攔截實例

    Vue+axios 實現(xiàn)http攔截及路由攔截實例

    這篇文章主要介紹了Vue+axios 實現(xiàn)http攔截及路由攔截 ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 淺談vue+webpack項目調(diào)試方法步驟

    淺談vue+webpack項目調(diào)試方法步驟

    本篇文章主要介紹了淺談vue+webpack項目調(diào)試方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • vue實現(xiàn)頁面渲染時候執(zhí)行某需求的示例代碼

    vue實現(xiàn)頁面渲染時候執(zhí)行某需求的示例代碼

    本文主要介紹了vue實現(xiàn)頁面渲染時候執(zhí)行某需求,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • vue-cli2.0轉(zhuǎn)3.0之項目搭建的詳細步驟

    vue-cli2.0轉(zhuǎn)3.0之項目搭建的詳細步驟

    這篇文章主要介紹了vue-cli2.0轉(zhuǎn)3.0之項目搭建的詳細步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Vue 不定高展開動效原理詳解

    Vue 不定高展開動效原理詳解

    本文主要介紹了Vue不定高展開動效原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評論