Vue(day11)
项目上线
对项目进行打包, 将打包后的内容,部署到服务器中
打包 : npm run build
把打好的包放到 http-server 里面,演示
第一次截图
- 介绍 vendor : 里面放一些第三方包 vue/vue-router/element-ui 包等
只要不是我们自己写的代码,都属于第三方 - 优化 :
2.1 优化打包的第三方 (CDN)
2.2 按需加载首屏加载时间,是衡量一个网站性能快慢的很重要的一个指标,
首屏加载时间越快,用户存留就越多,用户量就越高
如何提高加载速度呢?
//1. 只加载首屏中看到的内容, 没有看到的内容都不加载,需要用到的时候,再去加载
//2. 进来减少首屏的请求次数
//3. vue 项目打包的时候,如何实现按需加载功能 ?
// 实现说明 : vue 的异步组件(路由) 配合 webpack 代码分割的功能,很容易实现按需加载功能
// 如何在项目中,通过代码实现按需加载呢 ? 讲导入组件的位置, 改为动态加载
-
按需加载 :
参考 : vue-router => 路由栏加载
const Home = () => import('@/components/Home/Home.vue') -
打包查看 js 文件
第二次截取
- 查看多的 js 文件
- 重新打包运行,演示点击进入按需加载
- 打包 GoodsAdd 和 Goods 在一起的包
const Goods = () =>
import(/_ webpackChunkName:'goods' / '@/components/Goods/Goods.vue')
const GoodsAdd = () =>
import(/ webpackChunkName:'goods' _/ '@/components/GoodsAdd/GoodsAdd.vue')
第三次截图
- 名字是 goods
- 文件也少了一个
CDN
为什么打包后,第三方文件体积很大,因为第三方文件比较多
如何优化 ?? 不再将第三方文件 打包到 dist, 但是, 项目中还是要是要第三方文件,我们通过一个在线的
的第三方文件路径, 来引入这个文件,(CDN)
- 在 index.html 引入 CDN 文件
- 在 webpack.base.conf.js
externals : {
vue : 'Vue',
"vue-router" : "VueRouter"
}
-
其他配置
-
以后使用 :
4.1 bootstrap => bootCDN
4.2 https://www.jsdelivr.com/
4.3 官方文档
项目打包和优化
- 打包命令:
npm run build
按需加载
- 1 修改
router/index.js
中导入组件的语法
// 使用:
const Home = () => import('@/components/home/Home');
// 替换:
// import Home from '@/components/home/Home'
// 给打包生产的JS文件起名字
const Home = () =>
import(/* webpackChunkName: 'home' */ '@/components/home/Home');
// chunkName相同,将 goods 和 goods-add 两个组件,打包到一起
const Goods = () =>
import(/* webpackChunkName: 'goods' */ '@/components/goods');
const GoodsAdd = () =>
import(/* webpackChunkName: 'goods' */ '@/components/goods-add');
- 2 (该步可省略)修改
/build/webpack.prod.conf.js
中的 chunkFilename
{
// [name] 代替 [id]
chunkFilename: utils.assetsPath('js/[name].[chunkhash].js');
}
使用 CDN
-
1 在
index.html
中引入 CDN 提供的 JS 文件 -
2 在
/build/webpack.base.conf.js
中(resolve 前面)添加配置 externals -
注意:通过 CDN 引入 element-ui 的样式文件后,就不需要在 main.js 中导入 element-ui 的 CSS 文件了。所以,直接注释掉 main.js 中的导入 element-ui 样式即可
-
externals
配置:
externals: {
// 键:表示 导入包语法 from 后面跟着的名称
// 值:表示 script 引入JS文件时,在全局环境中的变量名称
vue: 'Vue',
axios: 'axios',
'vue-router': 'VueRouter',
'element-ui': 'ELEMENT',
BMap: 'BMap',
echarts: 'echarts',
}
import ElementUI from 'element-ui'
常用包 CDN
-
说明:
- 1 先在官方文档查找提供的 CDN
- 2 如果没有,在
https://www.bootcdn.cn/
或其他 CDN 提供商 查找
Quill
<!-- Include the Quill library -->
<script src="https://cdn.bootcss.com/quill/1.3.4/quill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script>
<!-- Include stylesheet -->
<link
href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.core.min.css"
rel="stylesheet"
/>
<link
href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.snow.min.css"
rel="stylesheet"
/>
<link
href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.bubble.min.css"
rel="stylesheet"
/>
Vuex
第一讲 : Vuex的介绍
vuex 是什么?
-
状态管理工具
-
状态即数据, 状态管理就是管理组件中的data数据
-
Vuex 中的状态管理工具,采用了 集中式 方式统一管理项目中组件之间需要通讯的数据
-
[看图]
如何使用
- 最佳实践 : 只将组件之间共享的数据放在 vuex 中, 而不是将所有的数据都放在 vuex 中 ,
- 也就是说:如果数据只是在组件内部使用的,这个数据应该放在组件中,而不要放在 vuex
- vuex 中的数据也是响应式的,也就是说:如果一个组件中修改了 vuex 中的数据,另外一个使用的 vuex 数据的组件,就会自动更新 ( vuex 和 localstorage的区别)
什么时候用 ?
-
官网
-
说明: 项目体量很小,不需要使用 vuex, 如果项目中组件通讯不复杂,也不需要使用 vuex
-
只有写项目的时候,发现组件通讯多,组件之间的关系复杂,项目已经无法继续开发了,此时,就应该使用 vuex
第二讲 : Vuex的基本使用
vuex的基本使用
- 安装 :
npm i vuex
- 引入 : 引入
vuex
之前一定要先引入vue
<script src="./node_modules/vuex/dist/vuex.js"></script>
- 实例化 store
- store 仓库 , 获取数据和操作数据都要经过 store
const store = new Vuex.Store()
- 操作数据
- 获取数据 :
store.state.num
- 操作数据 :
store.state.num = 300
- 虽然
store.state.count = 300
可以修改值 , 但是vuex 也有严格模式, - 添加严格模式 :
strict : true,
- 获取数据 :
- 使用 mutations
- 注册 :
mutations : {}
increament(state) { state.count = 20; }
- 默认第一个参数永远是 state
- 触发事件 :
store.commit('increament')
- 注册 :
vuex的传参
-
触发事件 :
-
# 传参最好传一个对象,多个值查看方便 store.commit('increament', { num: 400 })
-
事件
-
# payload 载荷 increament(state, payload) { state.count = payload.num }
vue和vuex的配合使用
需求 : 有个h1显示数字的标题, 点击按钮累加数字
- 先用vue做出来效果
- 再用vuex和vue配合使用
- 实例化vuex的store
- 实例化vue
- 把store挂载到vue上
- 操作数据
- h1展示数据 :
<h1>{{ $store.state.num }}</h1>
- 点击触发事件修改数据 :
this.$store.commit('addNum')
addNum(state) { state.num++ }
- h1展示数据 :
第三讲 : Vue脚手架3.0
安装 :
- 安装脚手架 2.x :
npm i vue-cli -g
- 安装脚手架 3.x :
npm i -g @vue/cli
- 检测脚手架版本号 :
vue -V / --version
创建一个项目
- 命令 :
vue create vuex-todos
(可视化 vue ui) - 可以选择默认配置或者手动配置
- 开发运行 :
npm run serve
- 发布构建 :
npm run build
第四讲 : 使用Vuex改版 TodoMVC
-
初始化项目
-
拷贝模板(todomvc-app-template)里的结构(section部分)和样式 (node_modules里的)
-
组件化
- 创建 todo-header.vue / todo-list.vue / todo-footer.vue + scaf结构
- app.vue 中 导入 :
import todoheader from "./components/todo-header.vue";
- 注册 :
components: { todoheader ,todolist ,todofooter }
- 使用 :
<todofooter></todofooter>
-
配置 vuex 管理 list
-
-
创建文件夹 store/store.js
-
安装 vuex
-
引入
-
vue安装vuex :
Vue.use(Vuex)
-
实例store, 并且导出 store
-
main.js 中引入并挂载到 vue 上
-
-
列表展示
-
删除任务
-
添加任务
-
修改任务
-
修改状态
-
计算属性(三个)
-
清除已经完成的任务
第四讲 : 如何使用 actions
- 官网介绍
- Action 类似于 mutation,不同在于:
- Action 可以包含任意异步操作。
- Action 提交的是 mutation,而不是直接变更状态。
- mutaions 里不只能使用同步,不能出现异步 (演示删除任务 里使用setTimeout 会报错)
- 演示1: actions 可以包含任意异步操作。 代码1
- 演示2: actions 不能直接变更状态 , 代码2 会报错
- 演示3 : actions 提交的是 mutation
# 都是 actions 里
//演示1 :
setTimeout(() => {
console.log('actions')
}, 0)
// 演示2 :报错
setTimeout(() => {
context.state.list = context.state.list.filter(
item => item.id != payload.id
)
}, 0)
// 演示3 : 提交 mutations
setTimeout(() => {
context.commit('delTodo', payload)
}, 0)
第五讲 : 常用的几个辅助函数
mapGetters
辅助函数
-
store.js 中的几个计算属性 :
-
let getters = { isFooterShow(state) { return state.list.length > 0 }, itemLeftCount(state) { return state.list.filter(item => !item.done).length }, isClearShow(state) { return state.list.some(item => item.done) } }
-
使用
mapGetters
-
在
todo-footer.vue
中 引入 :import { mapGetters } from "vuex";
-
将 store 中的 getter 映射到局部计算属性
computed: { ...mapGetters(["isFooterShow", "itemLeftCount", "isClearShow"]) }
- -
使用
-
-
以前通过属性 :
<footer v-show="$store.getters.isFooterShow">
-
现在通过辅助函数 :
<footer v-show="isFooterShow">
-
-
mapMutations
辅助函数
# 写在 methods
# 映射
...mapMutations(["delTodo", "updateTodo", "changeState"]),
# 起别名 (防止当前所在的函数名和这个mutaions名一致,会导致死循环)
...mapMutations({
deltodo: "delTodo",
updatetodo: "updateTodo",
changestate: "changeState"
}),
# 以后使用
this.deltodo({id}) 替代 : this.$store.commit('delTodo',{ id })
mapActions
辅助函数
# 写在 methods
# 映射
...mapActions(["asyncDelTodo"]),
# 起别名
...mapActions({
aDT: "asyncDelTodo"
}),
# 使用别名
this.aDT({ id });
# 如果没有起别名
this.asyncDelTodo({ id }); 替换 this.$store.dispatch('asyncDelTodo',{id})
反向代理
一 : 说明
- 解决跨域问题的方式 :
- JSONP == > 只能处理 get 方式
- CORS ==> 处理自己的服务器
- 反向代理 ==> 也很常用
- 说明
- 演示跨域问题
- 反向代理的原理
- 脚手架vue-cli 生成的项目中如何使用反向代理
二 : 演示跨域问题
-
在
todo-vuex
里的 app.vue 中 的js 代码区域演示 -
安装 axios
-
代码 :
// 演示跨域问题 /* eslint-disable */ import axios from 'axios'; axios.get('https://api.douban.com/v2/movie/in_theaters').then(res => { console.log(res) })
-
报错 :
Access to XMLHttpRequest at 'https://api.douban.com/v2/movie/in_theaters' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
-
报错原因
- 项目运行在 http://localhost:8080 // I Your application is running here: http://localhost:8080 - 发送ajax请求 : //域名是 https://api.douban.com/v2/movie/in_theaters - 出现跨域问题
三 : 反向代理的原理
四 : 演示
- 修改
config/index.js
配置文件
proxyTable: {
'/myapi': {
// 代理的目标服务器地址
// https://api.douban.com/v2/movie/in_theaters
// /myapi/movie/in_theaters
target: 'https://api.douban.com/v2',
pathRewrite: { '^/myapi': '' },
// 设置https
secure: false,
// 必须设置该项
changeOrigin: true
}
},
-
最终代码
// axios.get('https://api.douban.com/v2/movie/in_theaters').then(res => { axios.get("http://localhost:8080/api/movie/in_theaters").then(res => { console.log(res); });
-
最终配置 cli2.x :
proxyTable: { '/myapi': { // 代理的目标服务器地址 // https://api.douban.com/v2/movie/in_theaters // /myapi/movie/in_theaters target: 'https://api.douban.com/v2', pathRewrite: { '^/myapi': '' }, // 设置https secure: false, // 必须设置该项 changeOrigin: true } },
-
最终配置 3.X
- 根目录下 新建一个
vue.config.js
- 拷贝如下代码
module.exports = { devServer: { proxy: { '/myapi': { // 代理的目标服务器地址 // https://api.douban.com/v2/movie/in_theaters // /myapi/movie/in_theaters target: 'https://douban.uieee.com/v2', pathRewrite: { '^/myapi': '' }, // 设置https secure: false, // 必须设置该项 changeOrigin: true } } } } # 使用 axios.get('http://localhost:8080/myapi/movie/in_theaters').then(res => { console.log(res) }) axios.get('/myapi/movie/in_theaters').then(res => { console.log(res) })
- 根目录下 新建一个
-
重新启动 :
npm run dev