nuxt.js
追求完美,相信大家都是這樣的。因為前后端分離的弊端性,在項目構建時,瀏覽器並不會捕捉到項目的內容,所以開始,筆者決定引入nuxt.js文件來配合vue完成Server Slider Render博客系統開發。服務端渲染以下簡稱SSR,不知道nuxt的童鞋可以去nuxt官網了解一哈。
聲明:一下代碼案例結合vue理解。
第三方插件的使用?
剛入坑,感覺寸步難行。想運來的使用方式,編輯器並不會報錯。但是瀏覽器卻報的nuxt錯誤。
后來經過幾十根頭發的代價換來了插件的正確使用方式
-
demo引入第三方的特效插件
-
需要現在plugins中寫一個第三方文件的js文件,這里是筆者引入的一個vue的特效的插件,
-
在nuxt.config.js中進行引入
/*
** Plugins to load before mounting the App
*/
這里需要補充的是,ssr為是否開啟SSR
-
-
最后在組件中就可以使用:
-
<template>
<section class="container">
<vue-particles
color="#fff"
:particleOpacity="0.7"
:particlesNumber="60"
shapeType="circle"
:particleSize="4"
linesColor="#fff"
:linesWidth="1"
:lineLinked="true"
:lineOpacity="0.4"
:linesDistance="150"
:moveSpeed="2"
:hoverEffect="true"
hoverMode="grab"
:clickEffect="true"
clickMode="push"
class="lizi"
>
</vue-particles>
<nuxt />
</section>
</template>
最后查看效果如圖:


效果如上,成功引入。
補充這個時候發現是沒問題,但是當我們更改dom節點,放到到全屏的時候,依然可以,但是控制台爆出vue警告:
commons.app.js:13349 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render
這個坑,真的坑了我好久,最后才發現,有些插件是不支持SSR的,剛好vue-partiles就是其中之一。
解決辦法:引入時通過no-ssr標簽包裹就
<no-ssr><vue-particles color="#ffffff" :particleOpacity="0.7" :particlesNumber="80" shapeType="circle" :particleSize="4" linesColor="#fff" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150" :moveSpeed="2" :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push" class="lizi" > </vue-particles></no-ssr>
此組件只在客戶端呈現,意味着,使用該組件包裹的內容都不屬於SSR,在網頁源碼中都不可見。這點需要注意。
路由的配置
前言:這里要區別一下vue的路由,vue路由可自行配置,靈活方便。而nuxt構建的項目,路由的配置則是由pages文件夾目錄生成。
pages目錄自動生成路由
直接上圖,所謂一圖頂千言:


layouts
這個文件夾在路由的配置中也扮演了相當重要的角色。它又是干什么的呢?
layouts文件字面理解多布局,項目的整體框架一般都有其固定的底層Layouts Model,nuxt很好的實踐了這個思想。layouts文件夾的功能簡單說局勢防止通用的布局模型,可以為Error Model,Default Model,當然這也是最常用的。當然如果說開發響應式項目,可以多一個webAPP的底層布局。
這個時候就淫問了,局部跳轉,vue一般采用嵌套路由實現,這里怎么做呢?
default.vue
兩種方式:
-
layouts為底,引入header,footer固定,section部分作為<nuxt/>動態跳轉
default.vue為默認引入的布局模型,不需要刻意引入。
只需要在頁面中添加
<template> <section> This is my projects!; </section> </template> <script> export default { layout: 'login' } </script> <style lang="less" scoped> </style>
Layout: 構建的Layouts Model
實現的效果為頭部固定,底部固定,中間部分跳轉
-
路由的配置由pages目錄生成,我們是否可以修改pages目錄來完成嵌套路由呢?
這里,考慮到文件目錄的層級,博主這里並未采用此方法,單此方法確實可行。
這里給大家一個error的組件,大家可以直接賦值,不需要引如,在報錯時,該組件會默認執行
3.動態路由
暫未實踐
error.vue
<template>
<div class="error">
<!-- <img src="../assets/img/logo.png" alt="Nuxt.js Logo" class="logo" /> -->
<h1 class="title">
{{ error.statusCode }}
</h1>
<h2 class="info">
{{ error.message }}
</h2>
<nuxt-link to="/">首頁</nuxt-link>
</div>
</template>
<script>
export default {
props: ['error']
}
</script>
<style scoped>
.error {
text-align: center;
padding: 30px 0;
}
.title {
margin-top: 15px;
font-size: 5em;
}
.info {
font-weight: 300;
color: #9aabb1;
margin: 0;
}
a {
margin-top: 50px;
border: 1px solid #3084bb;
color: #3084bb;
font-size: 16px;
display: inline-block;
padding: 10px 20px;
border-radius: 4px;
}
</style>
對於不相鄰組件以及其他需求,狀態庫總是一個很好的狀態存儲工具。
回顧vue中vuex的使用,項目根文件夾建立store文件夾。創建index.js文件,而后在main.js主入口文件中引入該文件,並掛在到vue原型鏈上,往后余生,我們便可通過this.$store來使用
但是在nuxt中,並沒有main.js主入口文件,我們又如何使用呢?
官方注釋:
為了讓 Vue 使用 Vuex,我們引入
Vue和Vuex(Nuxt.js 已包含),這樣組件內就多了個$store屬性了
這個是官方解釋,說明Nuxt中已經包含了Vuex,我們只需要通過this.$store就可以訪問到。
demo:
store下新建index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // require('whatwg-fetch'); const store = () => new Vuex.Store({ state: { searchParams: '', }, mutations: { setSearch: function (state, params) { state.searchParams = params; } }, actions: { } }) export default store
<template>
<header>
<div class="search">
<input type="text" v-model="searchContent"><button @click="search(searchContent)">Search</button>
</div>
</header>
</template>
export default {
data() {
return {
searchContent: '',
}
},
methods: {
search(data) {
this.$store.commit('setSearch',data);
console.log(this.$store.state);
},
}
}
</script>

簡單的使用就是如此了,當然提交更改等操作與vue中vuex的操作都是一樣的,關鍵問題是如何引入。
權限篇
這里我將權限校驗分為兩部分一個是前端根據路由處理,一個是后端根據接口處理
前端做的處理如下:
有些頁面在不登錄的情況是不允許登錄的,在路由發生變化的時候進行判斷,是否含有token,如果有則進行next()跳轉,如果沒有則跳轉login
后端的處理如下:
針對於某些接口,在沒有登錄的情況下,某些接口是無法進行調用的,除非登錄成功token有效。如果前端在調用某接口的時候,先判斷是否攜帶token過來,且token是否有效,如果有效,
則繼續條用接口,如果token失效或者headers中沒有攜帶token則返回401並給出詳情提示'unAuthorization'
下來我們一步步進行處理,我們先進行前端的處理
-
middleware中間件的使用
官方解釋:中間件允許您定義一個自定義函數運行在一個頁面或一組頁面渲染之前。
每一個中間件應放置在
middleware/目錄。文件名的名稱將成為中間件名稱(middleware/auth.js將成為auth中間件)。
簡單說就是可以針對某一模塊或某一頁面進行設置中間件,而中間件的使用,則可以進行權限的一個校驗。
上Code:
import { isLogin } from '../util/assist';
export default function({ route, req, res, redirect }) {
let isClient = process.client;
let isServer = process.server;
let redirectURL = '/login';
if(isServer) {
let cookies = req.cookies;
let path = req.originalUrl;
if(path.indexOf('admin') !== -1 && !cookies.token) {
redirect(redirectURL);
}
}
if(isClient) {
if(route.path.indexOf('admin') !== -1 && !isLogin()) {
redirect(redirectURL);
}
}
}
isLogin
export function isLogin() { if (getCookieInClient('token')) { return true } return false } export function getCookieInClient(name) { let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) return unescape(arr[2]); else return null; }
代碼寫完了,我們在什么地方引用呢?
我們這里采用全局引用,引入的模塊的名稱就是中間件中文件的名稱。
nuxt.config.js
router: { middleware: 'adminAuth' },
這里之所以寫成admin是因為,個人項目的設置,admin為項目的管理模塊,都已admin開頭,所以這里統一設置。
后端又如何進行設置呢?
let jwt = require('jwt-simple');
const jwtSecret = require('../util/database.config').jwtSecret
const needAuth = require('../../util/api.config').needAuth
module.exports = function (req, res, next) {
let path = req.originalUrl.split('?')[0];
console.log('7',path);
console.log('8',needAuth);
//接口不需要登陸:直接next
if (needAuth.indexOf(path) == -1) {
return next();
}
//接口需要登陸
var token = req.headers['authorization'];
if (!token) {
return res.json({
code: 401,
message: 'you need login:there is no token'
})
}
try {
//解密獲取的token
let decoded = jwt.decode(token, jwtSecret);
//校驗有效期
if (decoded.exp <= Date.now()) {
return res.json({
code: 401,
message: 'you need login:token is expired'
});
}
next();
} catch (err) {
return res.json({
code: 401,
message: 'you need login:decode token fail'
})
}
};
api.config.js: 防止需要驗證的接口
jwtSecret: 可以為任意字符串
jwt-simple: token的生成加密與解析詳見:https://www.jianshu.com/p/d9a087349ed2
Mysql
-
模糊搜索
sqlTitle =
select * from articles where title like '%${params.search}%';;like操作符: LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配進行比較.
如果要模糊查詢,還要加上
通配符'%'
匹配以"nuxt"開頭的數據
select * from articles where title like 'nuxt&'匹配包含'nuxt'的數據select * from articles where title like '%nuxt%';匹配以'nuxt'結尾的數據select * from articles where title like '%nuxt';通配符二 '_'
和'%'類似,不過會做出一個字符的限制,限制字符為幾位
eg:
數據庫中含有數據
123,1234,12345.
'2_' 意思是以2開頭后面只有一位 結果為123
'_2' 意思是以2結果,前面只有一位 結果為 null,因為沒有2結尾的
-
場景:一個標簽表,一個文章表。
通過標簽的名稱去查,該標簽下所有的文章的id的行。
SELECT second.* from articles_tags first LEFT JOIN articles second on second.id = first.article_id WHERE tag = 'vue.js'
這個的意思是:查詢表二符合條件的所有數據,查詢條件呢?
符合條件的所有的tag的名稱的這一行的article_id。然后根據這個article_id去articles表中查詢相關的所有數據。
數據庫如圖:


advice
正如所見, MySQL的通配符很有用。但這種功能是有代價的:通配符搜索的處理一般要比前面討論的其他搜索所花時間更長。這里給出一些使用通配符要記住的技巧。
-
-
在確實需要使用通配符時,除非絕對有必要,否則不要把它們用 在搜索模式的開始處。把通配符置於搜索模式的開始處,搜索起來是最慢的。
-
仔細注意通配符的位置。如果放錯地方,可能不會返回想要的數
