為什么使用nuxt.js?
vue單頁面應用渲染是從服務器獲取所需js,在客戶端將其解析生成html掛載于
id為app的DOM元素上,這樣會存在兩大問題。
- 由于資源請求量大,造成網站首屏加載緩慢,不利于用戶體驗。
- 由于頁面內容通過js插入,對于內容性網站來說,搜索引擎無法抓取網站內容,不利于SEO。
Nuxt.js 是一個基于Vue.js的通用應用框架,預設了利用Vue.js開發服務端渲染的應用所需要的各種配置。可以將html在服務端渲染,合成完整的html文件再輸出到瀏覽器。
除此之外,nuxt與vue還有一些其他方面的區別。
路由
nuxt按照 pages 文件夾的目錄結構自動生成路由
vue需在 src/router/index.js 手動配置路由入口頁面
nuxt頁面入口為 layouts/default.vue
vue頁面入口為 src/App.vue
- webpack配置
nuxt內置webpack,允許根據服務端需求,在 nuxt.config.js 中的build屬性自定義構建webpack的配置,覆蓋默認配置
vue關于webpack的配置存放在build文件夾下
下圖為關于nuxt的簡單概述
nuxt是關于服務端渲染的,如若想讓組件在客戶端渲染,可以使用
<no-ssr></no-ssr>
將其包裹起來(該標簽最多只能包含一個子組件/元素)。
這樣在未獲取到內容時,頁面先采用<div class="no-ssr-placeholder" data-v-2a183b29=""></div>
占位,然后將獲取到的html覆蓋該占位
安裝sass
npm i node-sass sass-loader scss-loader --save-dev
vue文件中可直接使用
<style lang="scss" scoped>
</style>
sass文件如需解析,nuxt.config.js中配置css屬性
css: [
{
src: '~/assets/style/reset.scss',
lang: 'scss'
}
],
使用axios并跨域
- package.json
npm install @nuxtjs/proxy
nuxt 項目默認安裝axios, 所以只需安裝proxy即可
"dependencies": {
"@nuxtjs/axios": "^5.0.0",
"@nuxtjs/proxy": "^1.2.4",
}
- nuxt.config.js
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
proxy: {
'/api': {
target: 'http:www.xxx.com',
changeOrigin: true,
pathRewrite: {
'^/api ': ''
}
}
},
- index.vue
import axios from 'axios'
export default {
data () {
return {
page: 0
}
},
async asyncData () {
let data = await axios.get('http://localhost:3000/api/admin/list')
return {
page: data.data.page
}
},
}
注意
采用import axios from 'axios'
方式引入axios時,接口參數前須加baseURL -> http://localhost:3000
如果采取axios.get('/api/admin/game')
調用接口返回nuxt服務器錯誤,如下圖
1540541910156.jpg
封裝axios,解決每個請求前加baseURL
plugins/axios.js
import * as axios from 'axios'
let options = {}
// The server-side needs a full url to works
if (process.server) {
options.baseURL = `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`
}
export default axios.create(options)
index.vue
import axios from '~/plugins/axios'
axios.get('/api/admin/game')
引入第三方插件(vue-awesome-swiper)
npm install vue-awesome-swiper --save
plugins文件夾下新建awesome-swiper.js
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
Vue.use(VueAwesomeSwiper)
- nuxt.config.js引入css及js
css: [
'swiper/dist/css/swiper.css',
],
plugins: [
{ src: "~/plugins/awesome-swiper.js", ssr: false },
],
- 頁面初始化
<div v-swiper:mySwiper="swiperOption">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(banner, index) in banners" :key="index">
<img :src="banner">
</div>
</div>
<div class="swiper-pagination swiper-pagination-bullets"></div>
</div>
export default {
data () {
return {
banners: [
require('~/assets/img/1540892214119.jpg'),
require('~/assets/img/1540892214119.jpg'),
require('~/assets/img/1540892214119.jpg')
],
swiperOption: {
autoplay: true,
loop: true,
pagination: {
el: '.swiper-pagination',
},
}
}
},
}
引入第三方模塊(moment.js)
npm install moment --save
- vue頁面
import moment from 'moment'
export default {
mounted() {
moment.locale('zh-cn') // moment.js 默認為英文,可通過此方法設置中文
console.log(moment().format('dddd')) // 星期三
},
}
為避免每個頁面都引入moment,執行moment.locale('zh-cn')
,可將其定義為全局方法
- 在plugins文件夾下新建common.js
import Vue from 'vue'
import moment from 'moment'
let common = {
install (Vue) {
Vue.prototype.$op = {
'moment': (date) => {
let newMoment = new moment(date)
newMoment.locale('zh-cn')
return newMoment
}
}
}
}
Vue.use(common)
- nuxt.config.js
plugins: [
{ src: '~/plugins/common.js', ssr: false },
],
- vue頁面
this.$op.moment().format('dddd')
修改網站icon
icon.png文件存放在static文件夾下,nuxt.config.js中配置head屬性
head: {
link: [
{ rel: 'icon', type: 'image/png', href: '/icon.png' }
]
},
關于中間件
中間件存放于middleware文件夾下,按使用場景可分為全局中間件和單頁面中間件
//全局使用
module.exports = {
router: {
middleware: '中間件名稱'
}
}
//頁面單獨使用
export default {
middleware: '中間件名稱'
}
中間件執行流程順序:
nuxt.config.js -> 匹配布局 -> 匹配頁面
PS.關于查看NUXT 官網插件demo時遇到的問題
按照index.vue通過require('mini-toastr')
引入miniToastr,運行程序報錯如下
打印miniToastr發現為一Module對象,init掛載在其default屬性上
所以修改引入方法為
miniToastr = require('mini-toastr').default
When using ES6 imports (export default HeaderBar), the exported module is of the format {"default" : HeaderBar}. The import statement handles this assignment for you, however, you have to do the require("./mycomponent").default conversion yourself. The HMR interface code cannot use import as it doesn't work inline.
If you want to avoid that, use module.exports instead of export default.
關于如上介紹,測試關于兩種模塊的導出方法
方式一:export default
新建test.js文件
export default {
test: function () {
console.log('test')
}
}
vue頁面導入
let obj = require('~/plugins/con.js').default
obj.test() // 打印‘test’
let obj = require('~/plugins/con.js')
obj.default.test() // 打印‘test’
此時 require('~/plugins/con.js')
打印為
方式二:module.exports
const obj = {
test: function () {
console.log('test')
}
}
module.exports = obj
let obj = require('~/plugins/con.js')
obj.test() // 打印‘test’
此時 require('~/plugins/con.js')
打印為