【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)

写在开头

大家好,这里是 lionLoveVue,基础知识决定了编程思维,学如逆水行舟,不进则退。金三银四,为了面试也还在慢慢积累知识,Github上面可以直接查看所有前端知识点梳理, github传送门,觉得不错,点个Star★,好运连连,Offer终究鼠于你,持续更新中。另外,也可以关注微信公众号: 小狮子前端Vue,源码以及资料今后都会放在里面。

Vue基础


全局安装vue/cli脚手架

管理员身份运行cmd,执行如下代码:

npm install -g @vue/cli

yarn global add @vue/cli

命令行输入vue ui 打开可视化界面

使用默认default配置

用vscode打开项目,执行如下命令

npm/cnpm run serve

访问:http://localhost:8080/ 查看是否配置成功

自定义指令

推荐阅读:官方文档-自定义指令

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

组件

父子组件的通信方式

父组件传子组件,是在子组件使用props,然后再父组件,通过:=绑定变量

子组件传父组件,是在子组件使用自定义事件,例如:

//子组件配置
@click="$emit('patch(xxx)')"
//父组件配置
@patch="func"

如果是跨组件,不是父子组件关系,就使用 Vuex

slot

插槽在组件抽象设计中的应用:

原本组件不能嵌入html内容,但通过父子组件传递插槽即可实现

//父组件
slot="a"
//子组件
<slot name="a"></slot>

Vuex基础


Vuex简单来说就是多个组件共享数据,但是组件是不能直接操纵数据的,如下图所示,我们的数据放在紫色部分state里面(没有放在data里),操作数据源由红色部分Mutations完成,什么时候操控数据有黄色部分Actions来控制,这里就是由用户来操纵组件来触发 Actions ,最后,由 Actons 提交 Commit 通知改变数据源,来完成组件视图的更新渲染。
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第1张图片

安装Vuex

npm/cnpm i vuex

Koa2基础


koa-generator

管理员身份打开cmd,运行如下代码,全局安装

npm install -g koa-generator

使用git bash,在文件夹内创建项目

koa2 -e project_name

-e 表示使用ejs,不加和 node 一样

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第2张图片
接下来,执行安装命令

cd koa2_learn
npm install

安装&更新 fsevents

npm install --update-binary

run app命令:

DEBUG=koa2_learn:* npm start

执行后输出 node bin/www 说明服务端已经跑起来了

访问 http://localhost:3000/ 查看页面效果

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第3张图片
我们查看 package.json ,发现启动脚本是通过 npm scripts ,如果你想要自启动的话,执行如下命令:

npm run dev

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第4张图片
对于上述执行指令,devprd 必须使用 npm run xxx

与此同时,我们在 index.js 全局打印一下,加入如下代码:
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第5张图片

git bash 中执行如下命令

npm run dev

说明我们改变服务端脚本,服务能够自启动了
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第6张图片

Koa2中间件


图片来自Koa2官方,大致意思就是服务端接受客户端的 Request,经过服务端一些流程,然后 Response 返回给浏览器,其中每一个环,都是一个中间件。进来的时候会经过某个中间件,出去的时候也会经过,这样的机制就可以让中间件引用顺序和代码执行顺序不一致。
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第7张图片

mongoose基础


mongodb概念&安装

mongodb属于非关系型数据库,与mysql相对的(mysql是关系型数据库)

mongodb里面没有 table表,只有 Collections

原本mysql一行叫做 row,而在mongodb中叫做 document,原本一列叫做 cloumn,而现在叫做 fields

windows 10 安装教程:

推荐阅读:Windows 平台安装 MongoDB

注意

安装Install MongoDB Compass 不勾选,否则可能要很长时间都一直在执行安装,MongoDB Compass是一个图形界面管理工具,后面会去下载一个图形界面管理工具Robo3T

其它选项就默认选择 next 即可

找到下面位置下的两个 .exe 都点击运行一下好了… (启动服务应该是下面那一个)
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第8张图片

检测是否安装成功

访问:http://127.0.0.1:27017/ 是否出现如下界面:

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第9张图片

图形界面管理工具 Robo3T 安装与使用

官网地址

Studio windows下载地址

Robo 3T下载

进入安装页面后选择 easy 版本 ,然后选择你喜欢的主题风格,是明亮还是黑暗风格

进入图形化界面后,新建一个 connection,选择默认端口 27017,保存

mongoose 中文文档

参考:mongoose 4.5中文文档

在之前配置好的 Koa2 文件夹内(我的是koa2_learn文件夹) 打开 bash 界面,输入如下命令,安装 mongoose

npm i mongoose

连接数据库

接下来就是配置相关了

在项目根目录下创建 名为 dbs 的文件夹

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第10张图片
新建一个 config.js 文件,配置如下代码

module.exports = {
    dbs: 'mongodb://127.0.0.1:27017/dbs'
}

dbs 目录下创建 名为 models 的文件夹
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第11张图片
新建一个 person.js 文件,配置如下代码(此时的文件名对应着之后我们的“表名”,也就是 Collections

const mongoose = require('mongoose')

//创建模式 
let personSchema = new mongoose.Schema({
    name: String,
    age: Number
})

//创建模型
module.exports = mongoose.model('Person',personSchema)

然后在 app.js 中进行导入

const mongoose = require('mongoose')
const dbConfig = require('./dbs/config')

app.js 默认注释 routes 后面,添加第三行连接代码

// routes
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
mongoose.connect(dbConfig.dbs,{
  useNewUrlParser:true
})

基本配置就结束了,现在最好是重启一下koa服务,ctrl+c 退出,然后输入如下命令:

npm run dev

出现如下界面,说明配置是没有问题的,连接成功!
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第12张图片
接下来就是尝试写一个api试试,在 users.js 文件内配置如下代码

头部导入模型

//导入模型
const Person = require('../dbs/models/person')

自定义api接口

router.post('/addPerson',async function(ctx){
  //新建一个模型的实例
  const person = new Person({
    name: ctx.request.body.name,
    age: ctx.request.body.age
  })
  let code
  try {
    await person.save()
    code=0
  } catch (error) {
    code=-1
  }
  ctx.body={
    code
  }
})

调用接口。 curl 是一个shell 命令, -d命令表示是 post 请求 ,接下来是数据项,最后是api接口地址

curl -d 'name=chocolate&age=20' http://localhost:3000/users/addPerson


此时,打开Robo 3T,刷新一下我们的数据库,就能发现多了一个 dbs
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第13张图片
查看一下,是否有对应写入数据:
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第14张图片
上述过程,基本上把我们的后端服务和数据库进行了打通,后续我们只需要套着之前的例子来就好了,接下来再展示写一个api,因为上文是增加操作,也就是写操作,下文我们再来个读操作吧。

依旧是在 users.js 中加入如下代码

//数据库读取api
router.post('/getPerson',async function(ctx){
  const result = await Person.findOne({name:ctx.request.body.name})
  const results = await Person.find({name:ctx.request.body.name})
  ctx.body = {
    code: 0,
    result,
    results
  }
})

打开 bash ,执行如下命令:

curl -d 'name=chocolate' http://localhost:3000/users/getPerson

发现,会返回给我们json数据包,证明api接口实现
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第15张图片
最后,附上更新和删除api,亲测有效嗷

//更新api
router.post('/updatePerson',async function(ctx){
  const result = await Person.where({
    name:ctx.request.body.name
  }).update({
    age: ctx.request.body.age
  })
  ctx.body = {
    code: 0,
  }
})
//删除api
router.post('/removePerson',async function(ctx){
  const result = await Person.where({
    name:ctx.request.body.name
  }).remove()

  ctx.body = {
    code: 0,
  }
})

更多知识点请参考:mongoose 4.5中文文档

Redis基础


cookie 和 session 引入

这里就要扯到 cookiesession的相关知识点了,划重点啦!

服务端的程序如何去识别客户端的状态,大家知道,http是无状态的,推荐阅读:如何学好前端,白嫖知识

比如现在有个用户A,它访问了服务器程序,那服务器程序如何知道下一次再访问的时候还是A呢?

因此,对于这一块就要用到非常重要的概念,session,当然,这个session可不是浏览器的,而是服务器的,它是用来存储用户的信息的。

那么,服务器的 session是如何保持在客户端呢?

这个时候呢,又要引出另一个非常重要的概念,浏览器中的 cookie

综上所述,cookiesession 的关系是:服务端用 session 来保存用户的状态,然后客户端用 cookie 来保存 session ,服务器端把 session 种植到 cookie 中,然后下次访问时,cookie 会携带着 session ,进而达到一个身份认证的效果

redis概念&安装

上文我们知道了cookie 和 session 在浏览器和服务器端的作用,那么与我们redis 有什么关系呢?

想一想,既然是认证的功能,那我们服务端的session 应该存在哪呢,也许你会想着放入服务器端存储,放入内存当中,这确实是一种方式,没有问题,但当应用程序很大的时候,session 容量特别大的时候呢?例如某宝这样的呢?此时内存肯定不够用了,这个时候就需要一个容器来存储大容量的 session 了,此时存储数据库 redis就发挥了它的作用了!

关于数据库的话,上文也提到了mongodb,我们是不是也可以用这个呢?

这个的话,虽然也是一种方式,但我们要考虑读写性能问题,因为 redis快速读写类型的数据库,使用灵活方便,是 key-value 型的


为了更加了解redis,这里我就引用官方介绍了:

  • REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。

  • Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

  • 它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

安装教程

参考:redis安装教程

参考:windows下Redis的安装和配置–图文教程

koabash界面,执行如下命令,完成 koaredis 的连接

npm i koa-generic-session koa-redis
redis-server.exe redis.windows.conf

启动 redis 服务

一、[9980] 21 Apr 02:57:05.611 # Creating Server TCP listening socket 127.0.0.1:6379: bind: No error

解决方法:在命令行中运行

redis-cli.exe
127.0.0.1:6379>shutdown

二、Redis (error) NOAUTH Authentication required.解决方法

127.0.0.1:6379>auth "123456"
127.0.0.1:6379>shutdown
not connected>exit

然后重新运行 redis-server.exe redis.windows.conf ,启动成功!

参考:Redis启动报错:Creating Server TCP listening socket 127.0.0.1:6379: bind: No error

Nuxt.js基础


Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置。

基于Vue 2做的,包括Vue-Router,支持Vuex、Vue Server Render、vue-meta

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第16张图片

Nuxt.js工作流

下图源自Nuxt官网,简单介绍一下它的工作流程

更多内容,请参考:nuxtjs 英文官方文档

参考:nuxtjs 中文文档
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第17张图片
从浏览器发出一个请求,到最终服务端渲染完成,关于Nuxt的生命周期如下:

  • Incoming Request 浏览器发送一个请求
  • 服务端检查是否有 nuxtServerInit 配置项,有的话就会执行这个函数,其中包含一个标注: Store action 用来操作 vuex
  • 下一个环节就是中间件 middleware ,与路由相关,做任何你想要的功能
  • 预验证 validate() 可以配合高级动态路由,做一些验证,比如是否允许跳转某个页面
  • asyncData() & fetch() 获取数据,前一个是用来渲染vue component,即 vue组件的,后一个通常用来修改 vuex,即 Store
  • 有了数据,模板后,最后一步就是 Render 渲染了,方式是 SSR

Nuxt.js 安装

如果没有安装vue cli的话,先全局安装一下

npm/cnpm install -g @vue/cli-init
vue init nuxt-community/koa-template nuxt_learn(这里填入你自己的文件名)

安装完成后,依次执行如下命令

cd nuxt_learn
npm install # Or yarn
npm install --update-binary
npm install ajv@^6(可选项,如果有报warn,就装一下)
npm run dev

如果安装过程网络有问题,报错了,可以试试用 cnpm或者

nrm use cnpm

eslint版本问题: 需要更新eslint版本

解决:执行如下代码:

npm install eslint-plugin-html@^3

执行完如下步骤后,最后一步,打开服务:

npm run dev

babel编译版本有问题: 解决办法是升级[email protected][email protected]

npm install backpack-core@0.7.0 --save-dev

解决上述问题后,编译能成功,但是客户端依旧运行报错

解决办法是:在nuxt.config.js里找到eslint-loaderctx.isClient改成ctx.Client就可以运行了

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第18张图片

参考:解决vue init nuxt-community/koa-template项目,安装报错问题

解决完上述问题后,执行如下指令:

npm run dev

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第19张图片

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第20张图片
访问:http://localhost:3000/ 出现如下界面,代表配置成功 ✿✿ヽ(°▽°)ノ✿

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第21张图片
附:微信公众号:【小狮子前端】 回复【nuxt-learn】即可获取本节源码

知识拓展

当使用 SSR 时, mounted 只在浏览器端渲染,而在服务器端不会渲染 :浏览器通过axios请求的数据,只有 created 在开启SSR时会执行。

SSR原理:① 服务器端将编译好的内容(模板)下发(包括样式、内容、数据) ② 把异步获取的数据响应给浏览器端(把交互交给浏览器来完成)

SSR原理深入

我们打开页面源代码,查看一下:

服务器端渲染完页面后给浏览器端的html分了几个部分,第一个是样式 style ,第二个是模板内容,例如上图中圈中的蓝色部分,第三个是服务端拿到的数据结果,例如上图中圈中的红色部分,为什么服务端拿到的数据给到浏览器端呢?
这里我们得思考一个SSR的工作原理

如果不给数据的话,就是一个静态html模板,一个静态的内容,没有任何交互,那交互是在哪完成的呢?

交互是在浏览器端完成的,也就是说浏览器端会有一个入口,进行预编译,但不会再渲染页面了,因为服务器端已经在页面渲染过一次了。它要做的是创建一个虚拟的编译结果(可以理解为虚拟dom), 和服务器端传过来的结果进行对比,如果有区别,它会重新请求数据。在nuxt项目中都是一套文件,没有特别指定是在浏览器端运行还是服务端运行,也就是SSR常说的同构,浏览器端编译虚拟dom,也依赖于 vue 文件,因此模板是有的,而编译这个dom,需要的是额外的数据,此数据是服务器端渲染之前请求而来的数据,如果数据不同步在浏览器端,编译出来的结果必然和服务器端编译结果不一致

综上,服务器端异步获取的数据会同步在浏览器端,作对比,如果对比一致的话,浏览器端就会对对应的dom结点注册事件,达到交互作用。

更多内容,请参考:nuxtjs 英文官方文档

参考:nuxtjs 中文文档

以上,就是我们项目搭建所需的基础知识啦,已经整理完结啦,当然还有许多地方没有提及,读者可以去查阅一些官方文档来补充更多知识,下文我们将逐步深入全栈开发过程记录,制作不易,点赞收藏评论,一键三连一波~

项目搭建开始


配置环境

  • node
  • vue
  • npm
  • webpack
  • nuxt

创建项目

npm install -g npx
npx create-nuxt-app loveVueApp

使用 npx 可以帮助我们更快速的搭建项目环境,在你需要创建项目文件夹的地方 shift+鼠标右键 打开 powershell 窗口,执行上述命令,然后按照下列图片选择对应的模块:



【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第22张图片

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第23张图片





安装完成后,会提示你执行如下命令:

这里我们就执行开发环境的指令就好了

cd loveVueApp
npm run dev

另附上,生产环境的指令:

cd loveVueApp
npm run build
npm run start

访问:http://localhost:3000/ 会有一个nuxtjs的图标出现,代表环境搭配成功 ✿✿ヽ(°▽°)ノ✿

此时,再 ctrl+c 退出当前服务

执行如下命令,重新安装一下,防止版本问题等

npm install  --update-binary

重装之后,再跑一次服务,看能不能打开界面

npm run dev

增加 babel-node 处理(使用ES6的import指令问题)

创建好我们的基本项目后,我们还需要对我们所需要的模块进行更改。

例如,对应目标文件的第一行代码:

改为如下代码

import Koa  from 'koa'

于是,就会出现报错,无法识别
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第24张图片

在上文讲解 nuxtjs基础 我们是可以直接用 import 操作的,但当我们使用官方脚手架时,是没有处理这个 bug 的。下面来解释一下为什么会出现这个问题:

当我们使用命令 npm run dev 的时候,其实是用了 npmscript 的方法,如下图所示:

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第25张图片

可见使用了 node,并且不支持 import 操作,上文是因为使用了 babel 进行了处理,在这里官方脚手架时使用 node 来启动服务,没有经过 babel 处理,因此就不会识别 import 指令了。

解决上述问题

上文提到了是因为没有 babel处理,执行服务程序,那就自己加上去咯,具体如下:

devstart 后面添加 --exec babel-node

或者直接使用下面代码覆盖你的 scripts

"scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server --exec babel-node",
    "build": "nuxt build",
    "start": "cross-env NODE_ENV=production node server/index.js --exec babel-node",
    "generate": "nuxt generate"
  },

然后,在根目录下创建一个 .babelrc 的配置文件,然后给它指定一个指令集

{
    "presets":["es2015"]
}

有了代码还不行,还要再安装插件,执行如下命令

npm install babel-preset-es2015
npm install babel-cli -S

好了,有了 babel-node 后我们就能启动服务程序了,改成了我们常用的 ES6语法了

npm run dev

访问:http://localhost:3000/ 会有一个nuxtjs的图标出现,代表环境搭配成功 ✿✿ヽ(°▽°)ノ✿

解决 sass 导致编译出错问题

这个问题也依旧是脚手架带来的问题,解决方式就是安装几个插件,执行命令如下:

npm install sass-loader node-sass

PS:可能会有下述 warn

npm install eslint@^(版本号)  //(注意,这里是当你出现对应warn才执行)

我的是这种警告,因此依葫芦画瓢,执行下述命令

npm install sass@^1.3.0 fibers@>= 3.1.0

辅助工具安装

  • MongoDB
  • redis
  • Robo 3T

(上文基础部分有介绍安装教程,可以往回看一看对应模块 ↑)

远程仓库常用指令(整理)

  • 查看分支:git branch

  • 查看项目的分支们(包括本地和远程) git branch -a

  • 创建分支:git branch

  • 切换分支:git checkout

  • 创建+切换分支:git checkout -b

  • 合并某分支到当前分支:git merge

  • 提交 git commit -m ‘简介’

  • git push -u origin master

首页开发

需求分析

  • 模板设计(解决复用问题)

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第26张图片

  • 组件设计(如何拆分组件)

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第27张图片
如何节省网络请求?

上述流程图共进行了两次请求,另外,异步获取数据时,还会有闪一下,影响用户体验,同时浪费一次网络请求。解决办法就是当浏览器去请求服务器的时候,当浏览器去请求文档的时候,服务端 ip已经知道了,那个时候就可以拿到对应的城市,立即返回数据给浏览器。做法就是通过 vuex 来同步状态,然后通过 SSR 异步请求就能得到数据。

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第28张图片
类似于上文流程图,也是可以通过 vuex 来做
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第29张图片
属于静态模块,不需要我们异步获取数据,直接用 SSR 下发一下就ok。

  • 数据结构设计(依赖于数据和组件)

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第30张图片
pois表 城市推荐数据库
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第31张图片

  • 接口设计(与数据结构相对应)

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第32张图片

首页开发Header-城市定位服务设计

根据 Header 布局情况来看的话,我们在components文件夹下创建如下几个文件夹和文件(水印遮住的是 README

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第33张图片

导入css,然后打开 nuxt.config.js 进行配置
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第34张图片

项目开发可能遇到问题


重要提醒!

本篇文章能详细概述的地方有限,所以下文将会以讲重点部分为主,其余部分请参考本参考源码,已经开放,开发过程中按照分支进行开发,然后合并到 master 分支

仓库の传送门(戳一戳)

收藏 star 一波,✿✿ヽ(°▽°)ノ✿

关于项目中SMTP服务功能配置问题

如下图,所示,我们首先登陆自己的QQ,打开邮箱,然后去打开下面两项服务
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第35张图片
server/dbs/config.js 文件内更改为你自己的授权密钥和邮箱即可
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第36张图片

引入 mongoose

npm install mongoose

配置 users 接口

npm install koa-router koa-redis nodemailer

配置 axios

npm install axios

配置 passport

npm install koa-passport passport-local

关于项目中登录注册接口问题

passport 包内有 isAuthenticated()方法,因此在文档源码中没有定义过。

passport会把用户的信息对象放到 session 对象里面去,也就是 passport 会存储在 session 中,例如如下,如果是登录状态的话,那么session会有 passport,而 passport 会有 user

   //判断是否是登录状态
  if (ctx.isAuthenticated()) {
    const {username, email} = ctx.session.passport.user
    ctx.body={
      user:username,
      email
    }
  }
  • users.js

server文件夹 index.js文件中 加载相关包

import mongoose from 'mongoose'
import bodyParser from 'koa-bodyparser'
import session from 'koa-generic-session'
import Redis from 'koa-redis'
import json from 'koa-json'
import dbConfig from './dbs/config'
import passport from './interface/utils/passport'
import users from './interface/users'
import geo from './interface/geo'
import search from './interface/search'
import categroy from './interface/categroy'
import cart from './interface/cart'

加载指令:

npm install mongoose koa-bodyparser koa-generic-session koa-redis koa-json

Cannot read property ‘post’ of undefined 问题解决

注册那一个模块那里,我一点发送验证码,然后就报了这个错误,一开始以为接口写错了,还测试了一下,原来是因为 axios 没有在 nuxt 脚手架中配置

Cannot read property 'name' of undefined

nuxt.config.js 文件中配置如下:

module.exports = {
  modules: [
    '@nuxtjs/axios',
  ],

  axios: {
    // proxyHeaders: false
  }
}

解决之后,发送验证码,如下结果,有邮件发送过来 ✿✿ヽ(°▽°)ノ✿
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第37张图片

关于 win10 redis 报错 Permission denied

同样也是注册页面,当我们注册后,点击同意协议并注册,发现无法跳转到登录界面,而提示 已注册 ,看了半天,提示服务错误,于是一开打redis命令窗,报了这个错误,原来是默认设置了只可读不可写,按如下方式增加权限,解决了问题 ✿✿ヽ(°▽°)ノ✿

解决:去Redis的rdb文件查看文件属性,增加写入权限
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第38张图片
参考:Redis在Windows下的坑

关于win10 mongodb 导入.bat文件问题

网上说用如下指令,但是我还是没有导入成功,说是不存在这指令,但之前数据库都导入了 users

mongoimport -d student -c areas areas.dat

于是,我就打开了 Studio 3T 来试着导入,还算是成功了吧


我的做法是直接在左边那个 Collections 文件夹直接右键 选择 Add 操作,然后导入 .dat文件,不过导完之后会有后缀出现,于是我就重命名了一下。虽然看起来有点傻傻的做法,但也算是解决了吧 ✿✿ヽ(°▽°)ノ✿
【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第39张图片

关于 geo服务 接口签名

http://cp-tools.cn/sign

关于定位服务及切换城市 geo bug解决

在城市定位 geo 分支那里,报了如下两个错误,可让我焦头烂额啊,终于,找到了解决办法,特来写此模块,记录一下 ✿✿ヽ(°▽°)ノ✿

① 报错Classic mode for store/ is deprecated and will be removed in Nuxt 3.

② Error occurred when calling nuxtServerInit: socket hang up

第一个问题出现这种错误的原因是:nuxt3版本中已经移除了对原始vuex这种编程,出现这种错误的代码如下:

解决的办法如下: store 目录下的每个 .js 文件会被转换成为状态树指定命名的子模块 (当然,index 是根模块)。

(以下代码亲测有效,直接覆盖你的代码即可)

首先是目录结构修改,最新版的已经不需要另外加一个 models 文件夹了。

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第40张图片

index.js 文件:

export const actions = {
  async nuxtServerInit({
    commit
  },{req,app}) {
    const {status,data: {province,city}} = await app.$axios.get('/geo/getPosition')
    commit('geo/setPosition',status===200?{city,province}:{city:'',province:''})      
    const {status:status2, data: {menu}} = await app.$axios.get('/geo/menu')
    commit('home/setMenu',status2===200?menu:[])
  }
}

geo.js 文件无需修改

第二个问题,多半是因为你写好的 geo 相关接口没有在serve/index.js中进行导入和配置使用(我就是因为这个)

import geo from './utils/geo'
app.use(geo.routes()).use(geo.allowedMethods())

具体导入位置如下:

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第41张图片

【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)_第42张图片

参考:美团项目 — 定位服务及切换城市5

参考:nuxtjs中使用SSR开发关于前端vuex请求后台的问题

关于搜索框请求次数问题

我们当然不能没输入一个字符,就请求一次接口,因此我们需要弄一个延时函数

npm install lodash

引入库

import _ from 'lodash'

关于切换城市模块优化与实现

首先明确一载入切换城市界面,哪个是要进行请求的,那就是省份(第一级),此时可以使用ssr进行服务端渲染,页面载入后也跟着进行载入,但这里就直接使用vue中的Mouted生命函数完成这里的axios请求 ↓

mounted: async function() {
    let self = this;
    let {
      status,
      data: { province }
    } = await self.$axios.get("/geo/province");
    if (status === 200) {
      self.province = province.map(item => {
        return {
          value: item.id,
          label: item.name
        };
      });
    }
  }

联动逻辑,使用watch监听用户选择了什么省份

  //监听pvalue值,当省份发生改变的时候,可选城市也要跟着改变(联动)
  watch:{
    pvalue:async function(newPvalue){
      let self=this;
      let {status,data:{city}}=await self.$axios.get(`/geo/province/${newPvalue}`)
      if(status===200){
        self.city=city.map(item=>{
          return {
            value:item.id,
            label:item.name
          }
        })
        self.cvalue=''
      }
    }
  },

注意select下拉框的设计,如果你不设置 label 显示的还是 value 的值,但是如果你设置了 label 那输入框显示的就是 label 的值,但是你 v-model 拿的还是你 value 的值,所以在省份中复制也是将 id 赋值给 value 的,所以参数正确!
会二级联动,三级联动还会难吗?毕竟现在你只需要重点思考逻辑上的代码,而 DOM 结构E-UI已经随随便便完成了,只剩下你关联他们的代码而已

参考:美团项目 — 切换城市 7

通过项目挖掘知识点(整理)

koa2中的ctx是什么?

为了试图搞明白,用console.log将它输出

{ request:
   { method: 'GET',
     url: '/',
     header:
      { host: 'localhost:3000',
        connection: 'keep-alive',
        'cache-control': 'max-age=0',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'accept-encoding': 'gzip, deflate, sdch, br',
        'accept-language': 'zh-CN,zh;q=0.8' } },
  response:
   { status: 200,
     message: 'OK',
     header:
      { 'content-type': 'text/plain; charset=utf-8',
        'content-length': '25' } },
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/',
  req: '',
  res: '',
  socket: '' 
}

可见它主要包括 requestresponse 两部分。

ctx是context的缩写中文一般叫成上下文,这个在所有语言里都有的名词,可以理解为上(request)下(response)沟通的环境,所以koa中把他们两都封装进了ctx对象,koa官方文档里的解释是为了调用方便,ctx.req=ctx.request,ctx.res=ctx.response,类似linux系统中的软连接?最终执行还是request和response对象
body是http协议中的响应体,header是指响应头ctx.body = ctx.res.body = ctx.response.body

Koa 提供一个 Context 对象,表示一次对话的上下文(包括 HTTP 请求和 HTTP 回复)。通过加工这个对象,就可以控制返回给用户的内容。

Context.response.body 属性就是发送给用户的内容。

const Koa = require('koa');
const app = new Koa();

const main = ctx => {
  ctx.response.body = 'Hello World';
};

app.use(main);
app.listen(3000);

上面代码中,main函数用来设置 ctx.response.body 。然后,使用 app.use 方法加载main函数。

你可能已经猜到了,ctx.response代表 HTTP Response。同样地,ctx.request代表 HTTP Request。

运行这个 demo,访问 http://127.0.0.1:3000 ,现在就可以看到"Hello World"了。

参考:koa2中的ctx是什么?

koa2中 query 和 querystring

在 koa 中,GET请求获取请求数据request对象中的 query 方法和 querystring 方法, query方法返回的是格式化好的参数,querystring 方法返回的是请求字符串。

koa2如何获取get方式的路由参数,比如xxx?name=123 获取name值

ctx.request.query
// => {name: '123'}
ctx.query
// => {name: '123'}

ctx.requestKoa 请求对象。可以通过 querystring 获取请求路径中的 query 字符串,通过 query 获取格式化好的参数。
ctx.queryroute.query 的别名。

阅读过:nuxt - nuxtServerInit & 页面渲染前的store处理 & context

koa2 使用passport权限认证中间件

参考:koa2 使用passport权限认证中间件

序列化和反序列化

更多内容参考:了解护照序列化反序列化

故名思议就是将结构化的对象转换为字节序列,反之就叫做反序列化。

为什么要序列化和反序列化?

内存当中的对象是结构化的,当你需要将这个对象在网络当中传输的时候,或者要保存到文件或者数据库当中的时候,你就需要将它序列化成字节流,便于处理。

而反过来,传输过去之后,或者从文件和数据库里读取出来的时候,又要重新构建恢复出原来的对象。

类比就是,比如我们打电话,电线不能直接传声音,需要把声音转换为电流,过去再把电流转换为声音。

为什么utils/axios.js 要创建一个实例

以下内容参考: nuxt.js 官方中文文档

如果您的项目中直接使用了 node_modules 中的 axios ,并且使用 axios.interceptors 添加拦截器对请求或响应数据进行了处理,确保使用 axios.create 创建实例后再使用。否则多次刷新页面请求服务器,服务端渲染会重复添加拦截器,导致数据处理错误。

import axios from 'axios'
const myaxios = axios.create({
  // ...
})
myaxios.interceptors.response.use(function (response) {
  return response.data
}, function (error) {
  // ...
})

结尾


如若本文有瑕疵需修改的地方,请提出来,谢谢您的贡献!

欢迎关注微信公众号:小狮子前端Vue

谢谢您的支持!✿✿ヽ(°▽°)ノ✿

学如逆水行舟,不进则退

你可能感兴趣的:(Vue全家桶系列,Vue,技术栈)