商城系统
模块化的出现
传统的js中有大量的业务会放入一个js文件中进行封装,以及大量的mvc出现导致我们模块没有按照模块划分,
是开发难度加大,可读性差,同时不利于团队间协同开发
vue核心思想
数据驱动
组件化
vue框架和react框架对比
vue
- 模版和渲染函数的弹性选择
- 简单的语法和项目创建
- 更快的渲染和更小的提及
react
- 更适用于大型应用和更多的可测试性
- 同时用于web端 和pc端原声app
- 更加生态的圈带来更多支持和工具
相同点
- 利用虚拟dom实现快速渲染
- 轻量级
- 服务端渲染
- 易于集成路由的工具,打包工具以及状态管理工具
- 优秀的支持和社区
第10章 登录模块实现
登陆
cookie-parser插件,写入cookie
res.cookie()
将用户名和ID存到cookie中,
登出
清除cookie
node端做拦截,配置白名单
放行登陆登出和商品列表页,其他操作未登陆提示登陆
cookie-parser
判断用户是否登陆的接口
根据存入的用户ID去查询,有直接显示用户的名称,展示登陆状态,没有则未登陆
通用弹窗组建开发
- 使用插件方式全局挂载
- 使用插槽进行配合使用
第11章 购物车模块实现
11-1 购物车列表功能实现
接口实现主要采取node端通过cookie,拿到用的ID,去查询购物车列表,然后返回。findOne()
11-2 商品删除功能实现
这部分主要是购物车商品的删除。
服务端通过用户传过来的商品ID,
加上cookie中获取的用的ID去更新。
这里使用到了$pull
user.updateOne({
userId: userId
}, {
$pull: {
cartList: {
productId: productId
}
}
})
11-3 商品修改功能实现
这章节主要操作到的是商品用户的商品数量更改和选中的状态,这里状态储存在后端。
服务端通过更新子集来改变数据
user.updateOne({
userId: userId,
'cartList.productId': productId
}, {
'cartList.$.productNum': productNum,
'cartList.$.checked': checked,
})
11-4 购物车全选和商品实时计算功能实现
这里有个小技巧
总金额的改变
计算属性总遍历数组然后相加返回
全选功能
定义一个计算属性计算当前被选中的数量checkedCount
通过判断当前数组的长度是否等于选中的数量
全选修改接口查找用户ID数据库批量修改用户的选中状态
将字符串变成布尔值
第12章 地址模块实现
12-1 地址列表渲染实现 (上)
页面实现
12-2 地址列表渲染功能实现(下)
从cookie中取用户ID去查询用户所有地址列表
12-3 地址列表切换和展开功能实现
地址列表默认显示3条,点击显示更多,对后端传进来的数据进行截取
通过计算属性将数组进行slice。设置limit。
点击展开修改limit的值。等于默认值,将完整数组传给它,没有不做改变
点击默认选中。通过index属性,data声明变量==index
12-4 地址设置默认功能实现
通过更新数据库中的默认地址实现
其中注意每次数据更新结束后,都将已经更改为默认地址的框变红,对数组进行从新排列。将默认选中变成第一位
12-5 地址删除功能实现
数据库操作删除地址
需要注意,当用户将默认地址删除后,不能让他跳转订单确认页面,
在计算属性中去拿到默认选中的地址缓存起来,没有则提示选择默认地址
反之,从计算属性的缓存中拿到地址ID跳转订单页
第13章 订单确认模块实现
13-1 订单确认列表渲染功能实现
去数据库查询购物车列表,获取其中被选中的渲染订单列表
13-2 创建订单功能实现
首先是前端请求带来参数:总金额和默认地址ID
后端根据cookie拿用户ID,去查询得到用户地址info,再去遍历用户的商品列表,拿到已经默认选中的返回goodslist,最后返回
生成order,加入数据库订单列表。返回订单ID,跳转确认页面。
let order={
orderId: orderId,
orderTotal: orderTotal,
addressInfo: address,
goodsList: goodsList,
orderStatus: '1',
createDate: createDate
}
- 订单ID
订单ID主要是声明一个当前系统架构平台的代码
声明两个随机数,r1和r2
生成系统时间
架构代码+r1+系统时间+r2
第15章 基于Vuex改造登录和购物车数量功能
vuex
- 什么是vuex?
是一个专门为vue应用程序开发的状态管理器。
其实每个组建data中的变量都是可以称为状态,当项目庞大时,需要组建间通信,就会变得难以管理。所以我们可以将他们抽离出来放到vuex中,统一管理 - 为什么要用vuex?
当我们构建一个中大型的单页面应用程序时,vuex可以更好的帮我们在组建外统一管理状态
- vuex的核心概念?
state:数据源,载体
getter:类似computed,借助state中的数据操作返回新的数据
actions:actions提交的是Mutation,而不是直接操作数据。可以做一些异步的操作。Mutation必须是同步的
Mutation:更改store中的数据唯一的方法就是Mutation
Module:当项目大时,状态多时,我们可以通过将每个模块的数据拆分,最后通过Module进行组合
储存登陆状态和购车车信息
页面进入获取当前用户信息,用vuex保存起来,供每个页面使用。
购物车信息页面。登陆后加载。增加和删除通过在组建调用Mutation改变数据
第14章 订单成功模块实现
根据用户传进来的订单ID,利用cookie的用户ID去查询,没有用户,提示错误。有结果,去拿到用户的订单列表
length小于0 。提示此用户没创建订单
大于0.遍历订单列表,拿订单ID匹配到订单金额。金额小于0,提示,无此订单。大于返回用户数据
webpack
这里需求是通过配置webpack,打造出一款vue移动端toash插件多页面应用
vue插件
声明一个对象,这个对象必须有一个install方法。最后导出这个方法,必须这样做,才能被vue通过use去使用
在install方法中。通过在vue原型上挂载方法去使用继承
通过vue.extend去继承并返回一个新的实例。
通过new这个实例,将这实例挂载到body中
在这个实例上添加方法
-
入口文件配置
import TostComponent from './vue-toast.vue' let Toast = {} Toast.install = function (Vue, options) { var opt = { duration: 3000, } Vue.prototype.$toast = function (message, options) { if (typeof options == 'object') { opt = { ...options } } const ToastController = Vue.extend(TostComponent) let instance = new ToastController().$mount(document.createElement('div')) document.body.appendChild(instance.$el) instance.message = message instance.visible = true var timer; clearTimeout(timer) timer = setTimeout(() => { instance.visible = false setTimeout(() => { document.body.removeChild(instance.$el) }, 300) }, opt.duration) } Vue.prototype.$toast['show'] = function (message, options) { Vue.prototype.$toast(message, options) } } if (window.Vue) { Vue.use(Toast) } export default Toast
-
webpack.config.js
const path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { entry: path.join(__dirname, 'src/lib/index.js'), output: { filename: 'vue-toast.js', path: path.join(__dirname, 'dist'), library: 'vueToast', libraryTarget: 'umd' }, module: { rules: [{ test: /\.vue$/, loader: 'vue-loader', exclude: /node_modules/, options: { loaders: { scss: 'style-loader!css-loader!sass-loader' } } }, { test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }, plugins: [ new VueLoaderPlugin() ], mode: 'production' }
多页面应用
clean-webpack-plugin
清除每次打包生成的静态文件
- 配置入口和出口和plugin
配置css、es6语法、js+css代码合并压缩、引入第三方库
使用babel-loader。
路由
之前的路由是有服务端劫持将完成的内容返回给我们
前端路由是我们根据不同的url匹配相应的页面展示
一般在但页面应用的时候使用前端路由,大部分页面结构不变,只修改部分内容的时候使用
优点
用户体验好, 不需要每次从服务端请求,快速展示给用户
缺点
不利于seo
动态路由
path: '/index/:indexId',
获取内容:$route.params.indexId
嵌套路由
在路由下添加自路由
命名路由
在标签上添加
<router-link :to="{name:"helloWorld" }"></router-link>
编程式路由
用于js中,使用
this.$router.push({path:'list'})
this.$router.push("list")
this.$router.push({path:'list?id=123'})
this.$router.push({path:'list',query:{id:123}})
this.$router.go()
第6章 商品列表模块实现
图片懒加载
vue-lazyload
第7章 Node.js基础
node的特点
- 基于chorem的 v8引擎
基于v8。可以扩展性的高性能服务器,在处理高并发上有优势,和c语言在性能上不相上下
- 单线程
-
common.js规范
-
导出
- 默认导出 module.exports 类似es6 中的 export default - 直接导出 exports.a = 123 ES6中: expert let a=123
- 导入
var modA = require( "./foo" );
es6
import
-
- 使用js开发后段代码
可以想开发前端一样开发后端
- 非阻塞IO
7-2 创建http Server容器
-
http
- http.createServer
创建server后,客户端就可以访问了,可以创建静态服务
- http.ClientRequest
- http.createServer
-
URL
- url.format
- url.parse
将地址序列化
-
Util
- util.inspect
将对象转为字符串
- util.inspect
7-3 通过node加载静态页面
-
fs
// 创建服务 let server = http.createServer((req, res) => { // 拿到请求文件路径 let pathName = url.parse(req.url).pathname // 读取文件进行渲染 fs.readFile(pathName.substring(1), (err, data) => { if (err) { res.writeHead(404, { 'Content-Type': 'text/html' }) } else { res.writeHead(200, { 'Content-Type': 'text/html' }) res.write(data.toString()) } res.end() }) })
- 调用第三方接口
7-4 搭建基于Express框架的运行环境
mongoDB基本用法
二、集合的增删改查
- 增:db.user.insert({id:123,name:'hello',age:99})
- 改:db.user. update({id:123},{$set:{id:456}})
- 删:db.user.remove({id:123})
-
查:db.user.find({id:123})
- 查第一条数据:db.user.findOne({id:23})。如果多个满足,返回查找到的第一个
- 格式化查找数据:db.user.find({id:123}.pretty()
- 小于$lt: db.user.find({age:{$lt:100}})
- 大于$gt:db.user.find({age:{$gt:80}})
- 大于等于$gte:db.user.find({age:{$gte:99}})
- 等于$eq:db.user.find({age:{{$eq:99}})
- 小于等于$lte:db.user.find({age:{$lte:99}})
一、数据操作
- 查看数据库:show dbs
- 创建数据库:use demo
- 删除数据库:db.dropDatabase()
- 创建集合:方式1 =》db.createCollection("user");方式二=》db.user.insert({id:111,name:'miya'})
- 查看集合:show collections
- 删除集合:db.user.drop()
本地倒入数据库命令
mongoimport -d db -demo(数据库名字) -c users(集合名字) --file 路径
第9章 基于Node.js开发商品列表接口
9-1 Node的启动和调试方式
- node启动
- pm2
9-2 基于Express实现商品列表查询接口
-
创建models
用于保存model
goods.js
引入mongoose。
定义表模型const mongoose = require('mongoose') const Schema = mongoose.Schema; let userSchema = new Schema({ }) module.exports = mongoose.model('users', userSchema)
- mongoose
- 创建路由
-
基于mongoose,开发商品列表的查找功能
查询数据库find()
分页操作,使用skip=(page-1)*pagesize
limit(pagesize)
按照价格排序sort({ 'salePrice': sort})
最后倒出exec-
页面需求分析
- 列表查询 - 排序 - 价格筛选 - 页面滚动加载 - 子主题 5
- 数据库查询操作
find()
skip()
limit()
sort()
exec()
-
购物车功能
拿用用户ID去先去查询
在用传进来的商ID去查商品
路由需要注意,router写接口时,路径相对于goods下,/addCart
前端请求地址加上/goods/addCart
post请求参数通过req.body.xxx
get请求参数通过req.query.xxx
部署
后端部署
将server文件夹下面的内容上传到服务器
启动方式:
node bin/www
pm2
mac下node版本升级
安装npm i -g n
升级到稳定版本:n stable
最新lts版本:n lts
最新版本: n latset
升级到某个版本n 12.xx
vue.config.js
默认common.js语法。使用module.exports 导出
publicpath:默认‘/’,如果项目部署在二级目录,比如mt。设置‘/mt’
devserver:本地开发接口proxy代理
outputpath:改变打包后静态资源文件名称
indexpath:改变打包后入口html的文件名
lintonsave:本地开发如果不喜欢eslint,可以设置关闭
前端代码优化
axios
入口文件引入并挂载vue原型上,页面通过this去vue实例上调用axios方法即可
错误拦截
分别对业务代码和服务端端错误进行处理已经登陆拦截
router
给路由添加元信息。在路由前置守卫中监听状态。对于登陆拦截和页面title,通过改变添加meta属性。
vuex
koa
首选npm init,初始化项目
安装koa
创建入口文件app.js
引入koa。
创建实例,new koa()
引入插件koa-router,koa-logger,
koa-static,koa-views
app.use(ctx => {
ctx.body = 'hello koa2'
})
app.listen(3000)
webpack4
全局依赖和项目依赖的区别?
项目依赖:npm install sass-loader -save
开发依赖:npm install scss-loader - -save -dev
项目依赖是只vue,vuex等,即便生产环境也需要使用
开发依赖比如babel。webpack等。上线后打包成js资源之后就不需要了
为什么使用模块化
为了网站访问速度更多快,安全性更高,把一堆文件合成一个文件,减少访问请求。访问多,浏览器响应时间过长,用户体验就差
代码压缩,兼容性处理
传统没有模块化之前,我们需要手动把需要的js引入页面,尽管他们彼此没有引用关系,我们还是需要顺序引用
有了模块化之后,我们只需要遵循模块相互引用定义的规范即可 。
amd, require.js的规范
commons.node.js的规范
export/import ESmodule的规范
loader和plugin的区别?
loader是将A转为B,比如将把文本转为js。性质发生变化
plugin是同样的A转换成A,只不过A做了相应的处理。变成全新的A
output
当我们开发插件时,需要兼容用户在各个环境都可以被使用,所以可以设置library和libraryTarget
output: {
path: path.resolve(__dirname, 'build'),
filename: 'js/built.js',
library: 'demo',
libraryTarget: 'umd'
}
css兼容性问题
postcss-loader。
使用方法
webpack.config.js
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}]
}
package.json
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 version"
]
devserver
使用devserver的好处:
前端服务器(软件服务器)
阿里云,腾讯云他们属于硬件服务器,操作系统需要安装nginx作为软件服务器去访问前端资源
可以通过http协议加端口号访问
调用后端接口(不在服务端不能调接口)
第三方接口代理
-
node的作用?
前端开发环境
服务端编程语言- 为什么一定要把node.js作为开发环境呢?
我们项目开发需要安装很多插件,npm、cnpm、yarn
现在很多打包都基于webpack。weback的开发环境就是node.js - 服务端编程语言
我们可以把node.js作为服务端语言去开发不同的接口供前端使用
node是服务端编程。可以支持前端服务器,我们平时开发完项目,通常会将部署到服务器。服务器访问的是web容器一般是nginx,把nginx作为前端的node容器去访问,而在本地开发,我们可以通过webpack插件webpack-dev-server去搭建dev-server
- 为什么一定要把node.js作为开发环境呢?
-
常用配置
devServer:{ contentBase:__dirname+'dist',//服务端跟路径 host:'localhost',//服务器主机 port:8080,//服务器端口号 hot:true,//热更新 open:true,//默认打开 openpage:'index.html',//默认打开的页面 proxy:{ "/api":{ target:'XXXX', changeOrigin: true } } }
webpack打包vue项目
引入vue,vue-loader
webpack.config.js
const vueloaderplugin=require('vue-loader/lib/plugin')
new vueloaderplugin()
//vue页面中使用图片,可以通过配置url-loader的options去解决。(name,limit,esModlu)
使用copywebpackplugin去完成
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。