【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)
Vue全家桶+SSR+Koa2全栈开发仿美团学习笔记,目前达27035字数,提供本次学习源码
写在开头
大家好,这里是 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-model
和 v-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
通知改变数据源,来完成组件视图的更新渲染。
安装Vuex
npm/cnpm i vuex
Koa2基础
koa-generator
管理员身份打开cmd,运行如下代码,全局安装
npm install -g koa-generator
使用git bash
,在文件夹内创建项目
koa2 -e project_name
-e 表示使用ejs
,不加和 node
一样
接下来,执行安装命令
cd koa2_learn
npm install
安装&更新 fsevents
包
npm install --update-binary
run app命令:
DEBUG=koa2_learn:* npm start
执行后输出 node bin/www
说明服务端已经跑起来了
访问 http://localhost:3000/ 查看页面效果
我们查看 package.json
,发现启动脚本是通过 npm scripts
,如果你想要自启动的话,执行如下命令:
npm run dev
对于上述执行指令,dev
和 prd
必须使用 npm run xxx
与此同时,我们在 index.js
全局打印一下,加入如下代码:
在 git bash
中执行如下命令
npm run dev
说明我们改变服务端脚本,服务能够自启动了
Koa2中间件
图片来自Koa2官方,大致意思就是服务端接受客户端的 Request
,经过服务端一些流程,然后 Response
返回给浏览器,其中每一个环,都是一个中间件。进来的时候会经过某个中间件,出去的时候也会经过,这样的机制就可以让中间件引用顺序和代码执行顺序不一致。
mongoose基础
mongodb概念&安装
mongodb属于非关系型
数据库,与mysql
相对的(mysql是关系型数据库)
mongodb里面没有 table
表,只有 Collections
原本mysql一行叫做 row
,而在mongodb中叫做 document
,原本一列叫做 cloumn
,而现在叫做 fields
windows 10 安装教程:
注意
安装Install MongoDB Compass
不勾选,否则可能要很长时间都一直在执行安装,MongoDB Compass是一个图形界面管理工具,后面会去下载一个图形界面管理工具Robo3T
。
其它选项就默认选择 next
即可
找到下面位置下的两个 .exe
都点击运行一下好了… (启动服务应该是下面那一个)
检测是否安装成功
访问:http://127.0.0.1:27017/ 是否出现如下界面:
图形界面管理工具 Robo3T
安装与使用
进入安装页面后选择 easy
版本 ,然后选择你喜欢的主题风格,是明亮还是黑暗风格
进入图形化界面后,新建一个 connection
,选择默认端口 27017
,保存
mongoose 中文文档
在之前配置好的 Koa2 文件夹内(我的是koa2_learn文件夹) 打开 bash
界面,输入如下命令,安装 mongoose
npm i mongoose
连接数据库
接下来就是配置相关了
在项目根目录下创建 名为 dbs
的文件夹
新建一个 config.js
文件,配置如下代码
module.exports = {
dbs: 'mongodb://127.0.0.1:27017/dbs'
}
在 dbs
目录下创建 名为 models
的文件夹
新建一个 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
出现如下界面,说明配置是没有问题的,连接成功!
接下来就是尝试写一个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
查看一下,是否有对应写入数据:
上述过程,基本上把我们的后端服务和数据库进行了打通,后续我们只需要套着之前的例子来就好了,接下来再展示写一个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接口实现
最后,附上更新和删除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,
}
})
Redis基础
cookie 和 session 引入
这里就要扯到 cookie
和 session
的相关知识点了,划重点啦!
服务端的程序如何去识别客户端的状态,大家知道,http是无状态的,推荐阅读:如何学好前端,白嫖知识
比如现在有个用户A,它访问了服务器程序,那服务器程序如何知道下一次再访问的时候还是A呢?
因此,对于这一块就要用到非常重要的概念,session
,当然,这个session
可不是浏览器的,而是服务器的,它是用来存储用户的信息的。
那么,服务器的 session
是如何保持在客户端呢?
这个时候呢,又要引出另一个非常重要的概念,浏览器中的 cookie
。
综上所述,cookie
和 session
的关系是:服务端用 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)等类型。
安装教程
在 koa
的 bash
界面,执行如下命令,完成 koa
与 redis
的连接
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
Nuxt.js工作流
下图源自Nuxt官网,简单介绍一下它的工作流程
参考:nuxtjs 中文文档
从浏览器发出一个请求,到最终服务端渲染完成,关于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编译版本有问题: 解决办法是升级backpack-core@0.3.0
到backpack-core@0.7.0
npm install backpack-core@0.7.0 --save-dev
解决上述问题后,编译能成功,但是客户端依旧运行报错
解决办法是:在nuxt.config.js
里找到eslint-loader
将ctx.isClient
改成ctx.Client
就可以运行了
参考:解决vue init nuxt-community/koa-template项目,安装报错问题
解决完上述问题后,执行如下指令:
npm run dev
访问:http://localhost:3000/ 出现如下界面,代表配置成功 ✿✿ヽ(°▽°)ノ✿
附:微信公众号:【小狮子前端】 回复【nuxt-learn】即可获取本节源码
知识拓展
当使用 SSR
时, mounted
只在浏览器端渲染,而在服务器端不会渲染 :浏览器通过axios请求的数据,只有 created
在开启SSR时会执行。
SSR原理:① 服务器端将编译好的内容(模板)下发(包括样式、内容、数据) ② 把异步获取的数据响应给浏览器端(把交互交给浏览器来完成)
SSR原理深入
我们打开页面源代码,查看一下:
服务器端渲染完页面后给浏览器端的html分了几个部分,第一个是样式 style
,第二个是模板内容,例如上图中圈中的蓝色部分,第三个是服务端拿到的数据结果,例如上图中圈中的红色部分,为什么服务端拿到的数据给到浏览器端呢?
这里我们得思考一个SSR的工作原理 了
如果不给数据的话,就是一个静态html模板,一个静态的内容,没有任何交互,那交互是在哪完成的呢?
交互是在浏览器端完成的,也就是说浏览器端会有一个入口,进行预编译,但不会再渲染页面了,因为服务器端已经在页面渲染过一次了。它要做的是创建一个虚拟的编译结果(可以理解为虚拟dom), 和服务器端传过来的结果进行对比,如果有区别,它会重新请求数据。在nuxt项目中都是一套文件,没有特别指定是在浏览器端运行还是服务端运行,也就是SSR常说的同构,浏览器端编译虚拟dom,也依赖于 vue
文件,因此模板是有的,而编译这个dom,需要的是额外的数据,此数据是服务器端渲染之前请求而来的数据,如果数据不同步在浏览器端,编译出来的结果必然和服务器端编译结果不一致。
综上,服务器端异步获取的数据会同步在浏览器端,作对比,如果对比一致的话,浏览器端就会对对应的dom结点注册事件,达到交互作用。
以上,就是我们项目搭建所需的基础知识啦,已经整理完结啦,当然还有许多地方没有提及,读者可以去查阅一些官方文档来补充更多知识,下文我们将逐步深入全栈开发过程记录,制作不易,点赞收藏评论,一键三连一波~
项目搭建开始
配置环境
- node
- vue
- npm
- webpack
- nuxt
创建项目
npm install -g npx
npx create-nuxt-app loveVueApp
使用 npx
可以帮助我们更快速的搭建项目环境,在你需要创建项目文件夹的地方 shift+鼠标右键
打开 powershell
窗口,执行上述命令,然后按照下列图片选择对应的模块:
安装完成后,会提示你执行如下命令:
这里我们就执行开发环境的指令就好了
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'
于是,就会出现报错,无法识别
在上文讲解 nuxtjs
基础 我们是可以直接用 import
操作的,但当我们使用官方脚手架时,是没有处理这个 bug
的。下面来解释一下为什么会出现这个问题:
当我们使用命令 npm run dev
的时候,其实是用了 npm
的 script
的方法,如下图所示:
可见使用了 node
,并且不支持 import
操作,上文是因为使用了 babel
进行了处理,在这里官方脚手架时使用 node
来启动服务,没有经过 babel
处理,因此就不会识别 import
指令了。
解决上述问题
上文提到了是因为没有 babel
处理,执行服务程序,那就自己加上去咯,具体如下:
在 dev
和 start
后面添加 --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 <name>
-
切换分支:
git checkout <name>
-
创建+切换分支:
git checkout -b <name>
-
合并某分支到当前分支:
git merge <name>
-
提交 git commit -m ‘简介’
-
git push -u origin master
首页开发
需求分析
- 模板设计(解决复用问题)
- 组件设计(如何拆分组件)
如何节省网络请求?
上述流程图共进行了两次请求,另外,异步获取数据时,还会有闪一下
,影响用户体验,同时浪费一次网络请求。解决办法就是当浏览器去请求服务器的时候,当浏览器去请求文档的时候,服务端 ip
已经知道了,那个时候就可以拿到对应的城市,立即返回数据给浏览器。做法就是通过 vuex
来同步状态,然后通过 SSR
异步请求就能得到数据。
类似于上文流程图,也是可以通过 vuex
来做
属于静态模块,不需要我们异步获取数据,直接用 SSR
下发一下就ok。
- 数据结构设计(依赖于数据和组件)
pois表
城市推荐数据库
- 接口设计(与数据结构相对应)
首页开发Header-城市定位服务设计
根据 Header
布局情况来看的话,我们在components
文件夹下创建如下几个文件夹和文件(水印遮住的是 README
)
导入css,然后打开 nuxt.config.js
进行配置
项目开发可能遇到问题
重要提醒!
本篇文章能详细概述的地方有限,所以下文将会以讲重点部分为主,其余部分请参考本参考源码,已经开放,开发过程中按照分支进行开发,然后合并到 master
分支
收藏 star
一波,✿✿ヽ(°▽°)ノ✿
关于项目中SMTP服务功能配置问题
如下图,所示,我们首先登陆自己的QQ,打开邮箱,然后去打开下面两项服务
在 server/dbs/config.js
文件内更改为你自己的授权密钥和邮箱即可
引入 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
}
}
解决之后,发送验证码,如下结果,有邮件发送过来 ✿✿ヽ(°▽°)ノ✿
关于 win10 redis 报错 Permission denied
同样也是注册页面,当我们注册后,点击同意协议并注册,发现无法跳转到登录界面,而提示 已注册
,看了半天,提示服务错误,于是一开打redis命令窗,报了这个错误,原来是默认设置了只可读不可写,按如下方式增加权限,解决了问题 ✿✿ヽ(°▽°)ノ✿
解决:去Redis的rdb文件查看文件属性,增加写入权限
参考:Redis在Windows下的坑
关于win10 mongodb 导入.bat文件问题
网上说用如下指令,但是我还是没有导入成功,说是不存在这指令,但之前数据库都导入了 users
mongoimport -d student -c areas areas.dat
于是,我就打开了 Studio 3T
来试着导入,还算是成功了吧
我的做法是直接在左边那个 Collections
文件夹直接右键 选择 Add
操作,然后导入 .dat
文件,不过导完之后会有后缀出现,于是我就重命名了一下。虽然看起来有点傻傻的做法,但也算是解决了吧 ✿✿ヽ(°▽°)ノ✿
关于 geo服务 接口签名
关于定位服务及切换城市 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
文件夹了。
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())
具体导入位置如下:
参考: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已经随随便便完成了,只剩下你关联他们的代码而已
通过项目挖掘知识点(整理)
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: '<original node req>',
res: '<original node res>',
socket: '<original node socket>'
}
可见它主要包括 request
和 response
两部分。
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中 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.request
是 Koa
请求对象。可以通过 querystring
获取请求路径中的 query
字符串,通过 query
获取格式化好的参数。
ctx.query
是 route.query
的别名。
阅读过:nuxt - nuxtServerInit & 页面渲染前的store处理 & context
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
谢谢您的支持!✿✿ヽ(°▽°)ノ✿
学如逆水行舟,不进则退
更多推荐
所有评论(0)