前言
当前总结是本人在业余学习与实践过程后的总结与归纳,旨在检验自己的积累,也方便忘记时查阅,同时也希望能帮助那些这方面知识匮乏的同行门,总结是基于 vue2.x
,vue-cli3.x
,主要记录些,vue
常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuex
,vue-router
等日常工作中时常用到的东西,也有些常用的插件
和开发工具
的介绍与使用,以及部分性能优化
的建议与实践,如有不对,或不足的地方,也请各位大神,指出来,学习学习。
目录
1. 基础
1.1 理解mvvm
1.2 常用指令
3. 性能优化
4. 插件的介绍和使用
1. 基础
m
是 vue
实例中的 data
,自定义的数据或后端返回的数组不是后端 mvc
里的model
概念不同vm
是 vue
的实例 m
和 v
之间的调度者是 mvvm
的核心思想v
是 html
要渲染的v-cloak
解决 {{}} 插值闪烁问题v-text
会先执行 覆盖 元素中原本的内容 但是插值表达式只会覆盖自己的占位符,默认不会闪烁v-html
渲染 html 标签 覆盖元素中原有元素内容v-bind
: 简写为: 用来绑定数据 可以写合法的 js 表达式v-on
: 简写为 @
用来点击事件stop
阻止冒泡 :外层和里层都有方法 点击里层会产生冒泡,也会触发外层的事件。顺序 从里到外产生事件prevent
阻止浏览器默认行为 :a
标签有浏览器默认行为。capture
捕获事件 :点击里层先触发外层再触发里层 顺序从外到里产生事件self
只触发自己本身的事件 不会产生冒泡和捕获事件 类似于阻止冒泡 但只针对自己那一层 最外层还是会被最里层冒泡冒到 stop
是阻止所有层次once
事件只执行一次v-bind
: 数据的单向绑定v-modle
:数据的双向绑定 这个只能用于表单元素中tips: 表单元素 radio
text
address
email
select
checkbox
textarea
1、数组带对象
<div :class="[classA,classB,{'classC':flag}]" >
data(){
return{
flag:true
}
}
tips: 可以在类中的数组中写三元表达式,但推荐使用对象来代替它控制是否渲染
2、单纯的对象
<div :class="{classA:falg1,classB:flag2}" />
data(){
return{
falg1:true,
falg2:true
}
}
3、数组带三元
<div :class="['ac','bd',falg?'active','']" / >
data(){
return{
falg:true,
}
}
4、对象升级
<div :class="classObj" />
data(){
return{
classObj:{classA:falg1,classB:flag2}
}
}
tips: 直接使用一个对象数组来控制样式
5、使用 style
的对象来实现样式的修改
<div :class="styleObj" />
data(){
return{
styleObj:{color:red}
}
}
6、使用 style
的数组带对象来实现样式的修改
<div :class="[styleObj1,styleObj2]" />
data(){
return{
styleObj1:{color:red},
styleObj2:{color:red}
}
}
可以遍历: 普通数组,对象数组,对象,还可以是数字
<div v-for='(item,key,index) in object' :key='index'>
{{item}}--{{key}}--{{index}}
</div>
<div v-for='(count in 10)'> </div>
tips: 在遍历对象的时候有多个 index
索引,遍历数字时是从 1 开始的。绑定 key
时属性值必须是 number
或者 string
v-if
有较高的切换性能 , 适合元素可能永远不会被用户看到v-show
有较高的初始渲染消耗,适合元素频繁切换vue-devtools
插件,使用这个插件并设置插件,允许访问文件网址。会在调试中出现vue相关的东西debugger
直接写可以调试<div v-for='(item,key) in object' :key='index'>
{{item | dateFormat}}
</div>
<div v-for='(count in 10)'> </div>
全局
vue.filter('过滤器名称',function(){
})
私有(局部)
filters:{
dateFormat:function(data,param){
do some
}
}
tips:
data
就是 |
第一个参数已经被定死了,永远是, 管道左边要被转换的数据,param 是过滤方法传进来的其他参数,过滤器采用就近优先原则,如果私有和全局的名称一样就优先采用私有的。padstart
和 padend
es6
的补 0
方法简单的过滤用过滤器
,复杂点用方法
,能用计算属性用计算属性
,有缓存,能提高性能<input @keyup.enter='方法名'></input>
tips: enter
可以换成键盘上的任何一个值,只要去找相关的键盘码,就都可以使用,推荐设置个别名,放在没有按钮操作的模板。
Vue.config.keyCodes.f2=113
, 就可使用了
tips: f2
修饰符是 vue
里没有定义的自己创建。
定义的指令都要按规定去创建在 bind
和 inserted
还有 updated
中去创建
Vue.directive('focus'{
//每当指令绑定到元素上的时候,会立即执行bind 函数,只执行一次,
注意:在元素刚绑定元素的时候,还没有插入到dom中去,这时候,调用focus方法没有作用,即放在focus 放在bind中是不起作用 的
bind:function(el,binding){
el.style.color=binding.value
},
//表示元素插入到dom中的时候,只执行一次
inserted:function(){
el.focus() js行为放在这里去创建
},
//当组件更新的时候,可能会触发多次
updated:function(){},
})
tips:
参数1
指令名称,在定义的时候,指令名称前面不需要加v-前缀,但是调用的时候,必须在指令名称前加v-前缀;参数2
:是一个对象,在这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作el
, el
是代表被bind
绑定的元素,el
是个原生的js
对象第二个参数可以是用户传进来值 bingding.value
directives:{
'指令名':{
bind:function( el,b){
}
}
}
3. 简写
'指令名':function(el,binding){
} //注意这个function 等同于 把代码写到bind和update中去
tips: 样式相关的指令放在 bind
中,js
行为相关的放在 inserted
中比较合适,防止指令不生效。使用场景 写组件时可以用这个去改样式
beforeCreate()
:这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它...created()
: 这是遇到的第二个生命周期函数...beforeMount()
:这是遇到的第3个生命周期函数,表示 模板已经在内存中编辑完成,但是尚未把模板渲染(挂载)到页面中。在 beforeMount
执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串。就像{{text}}这样mounted()
:这是遇到的第四个生命周期函数,表示内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了。只要执行完这个生命周期,就表示整个 vue
实例已经初始化完毕了,此时,组件已经脱离了创建阶段,进入到了运行阶段。beforeUpdate()
:这时候表示,我们的界面还没有被更新[但数据已经被更新了页面中显示的数据,还是旧的,此时 data
数据是最新的。页面尚未和最新的数据保持同步update()
: 这一步执行的是 先根据 data
中最新的数据,在内存中重新渲染出一份最新的内存 dom
树,当最新的内存 dom
树被更新后,会把最新的内存 DOM
树重新渲染到真实的页面中去,这时候,就完成了数据 data(model层)->view(视图层)
的更新,页面和 data
数据已经保持同步了,都是最新的。beforeDestory
:当执行 beforeDestory
钩子函数的时候,Vue
实例就已经从运行阶段,进入到销毁阶段, 当执行 beforeDestroy
的时候,实例身上所有的 data
和所有的 methods
以及过滤器、指令...
都处于可用状态,此时,还没有真正执行销毁的过程。destroyed
: 当执行这个函数的时候,组件已经被完全销毁了,此时,组件中所有的数据,方法,指令,过滤器...
都已经不可用了1. vue的内置动画
<style>
.v-enter,
.v-leave-to{
opacity:0;
transform:translateX(150px) --这东西是位移
}
.v-enter-active,
.v-leave-active{
transition:all 0.4s ease;
}
</style>
<transition name='my'>
<h3 v-if="flag"></h3>
</transition>
<script>
data(){
return {
flag:false
}
}
</script>
2. 使用第三方类实现动画
<transition enter-active-class="bounceIn"
leave-avtive-class="bounceOut" duration='200'
>
<h3 v-if="flag" class="animated" ></h3>
</transition>
3. 在属性中声明js钩子 实现半场动画(只需要进场,不需要离场)
<transition
<div
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
<transition
<div
v-show="flag"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
<script>
methods:{
beforeEnter(el){
//动画入场之前,此时动画尚未开始, 可以在beforeEnter中设置元素开始动画之前的初始位置
el.style.transform=
"translate(0,0)"
},
enter(el,done){
/*这句话,没有实际的作用,但是,如果不写,出不来动画效果,可以认为 这个会强制刷新动画,ofset触发了重绘重排导致动画更新了*/
el.offsetWidth
el.style.transform=
"translate(150px,450px)"
el.style.transition='all 1s ease'
/*这里的done 代表着
afterEnter的引用,
这个会立即执行afterEnter 否则会有延时
*/
done()
},
afterEnter(el){
/*动画完成之后,会调用afterEnter */
this.flag=!this.flag
}
}
</script>
4. 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for
循环渲染出来的,不能使用 transition
包裹,需要使用 transitionGroup
<transition-group appear tag='ul'>
<li v-for >
<li>
</transition-group>
.v-enter,
.v-leave-to{
opacity: 0;
transform:translateY(80x);
}
.v-enter-active,
.v-leave-active {
transition: all 0.6s ease;
}
/*离开后下一个东西没有动画使用这个可以使用动画实现下一个东西渐渐地飘上来的效果,要和 v-leave-active的absolute 配合 固定写法*/
.v-move {
transition:all 0.6s ease
}
.v-leave-active{
/* absolute 有个特点元素默认宽度就是最小值,要在元素上添加width:100%*/
position:absolute;
}
<transition mode="out-in">
<component :is="comName" >
</component>
</transition>
tips:
v-enter
[这是一个时间点] 是进入之前,元素的起始状态,此时还没有开始进入v-leave-to
[这是一个时间点]是动画离开之后,离开的终止状态,此时,元素动画已经结束了v-enter-active
[入场动画的时间段]v-leave-active
[离场动画的时间段]animated
是个动画库 新版本似乎不需要加入duration=200
来表示动画的时间 如果只写一个表示统一配置了开场和离场时间 用 对象
可传入c入场和离场 duration="{enter:200,leave:400}"
appear
属性,实现页面刚展示出来,入场时候的效果transition-group
元素,设置tag
属性指定 transition-group
渲染为指定元素,如果不指定tag
属性,默认,渲染为span
标签mode="out-in" 先过渡再进来,防止有阴影,通过
mode`来设置过渡方式。注意:最外层一定要用transition
包裹着,动画似乎升级了,可以在transition
标签中加入name
属性,并且在css
样式中把v
,替换为你的name
属性值。
1.使用Vue.extend 来创建全局的Vue组件
var coml=Vue.extend({
template:'<h3>这是使用Vue.extend 创建的组件</h3>'
})
//第一个参数组件名称,第二个参数创建出来的组件模板对象
Vue.component('myComl',coml)
<my-coml><my-coml/>
2.使用 vue.component 来创建组件
Vue.component('mycom2',{
template:'<div>
<h3>
这是直接使用Vue.component 创建出来的组件
</h3>
</div>'
})
3.使用 template 来创建组件
<template id='tmp1'>
<div>
<h1>
这里通过template元素,在外部定义的组件结构,这个方式,有代码的智能提示和高量
</h1>
</div>
</template>
Vue.component('mycom3',{
template:'#tem1'
})
4.私有组件 componment
<template id='temp2'>
<h1>这是私有login组件</h1>
</template>
componment:{
login:
{
template:'tmpl2'
}
}
Vue.component
定义了全局组件的时候,组件名称使用了驼峰命名,在引用的时候大写的驼峰要改为小写,同时两个单词之间 使用-链接Vue.component
第一个参数:组件的名称,将来在引用组件的时候,就是一个标签形式来引入的,第二个参数:Vue.extend
创建的组件,其中 template
就是组件将来要展示的内容template
属性指向的模板内容,必须有且只能有唯一的一个根元素。data
数据data
和实例中的 data
有点不一样,实例中的 data
可以为一个对象,但是组件中的 data 必须是一个方法。data
除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行。data
数据,使用方式,和实例中的 data
使用方式完全一样!data
为什么必须是个方法返回个对象呢?因为要确保每个实例
里的数据是唯一的,独有的。如果 data
里的数据是放在实例外部
的,会被其他实例
共享。1、组件里的切换 可以用 v-if
和 v-else
进行切换即标签页切换
<a href=""
@click.prevent="flag=true"
>
登录
</a>
<a href=""
@click.prevent="flag=flase"
>
注册
</a>
<a href=""
@click.prevent="flag=flase"
>
注册
</a>
2、vue
提供了 component
,来展示对应名称的组件
//component 是一个占位符
:is属性,可以用来指定要展示的组件的名称 写死的时候这个组件名要是个字符串,动态绑定时key普通写法就好,但value必须是字符串。
<component :is="'componentId'">
</component>
<component :is="oneName">
</component>
data(){
return{
oneName:"login",
}
}
1、父子组件传值,通过 v-bind:(:)
来传值,通过 props
来接收值
2、父组件用事件绑定机制传递 方法
给子组件— v-on
简写 @
//父组件中
<component-name
:children='children' //传值
@handle='show' //绑定方法
>
</component-name>
data(){
return(){
children:11
}
}
methods:{
show(data){
}
}
3、emit
英文原意: 是触发,调用,发射的意思。
@handle=show
父组件传show
方法给子组件。
子组件接收父组件的方法,并用$emit
把子组件的值传给父组件
//子组件中
methods:{
handle(){
this.$emit('func',{
age:1,
name:'搞事'
})
}
}
4、在父组件中接收子组件所有参数的同时,添加自定义参数
1.子组件传出单个参数时:
// 子组件
this.$emit('test',this.param)
// 父组件
@test='test($event,userDefined)'
2.子组件传出多个参数时:
// 子组件
this.$emit('test',this.param1,this.param2, this.param3)
// 父组件 arguments 是以数组的形式传入
@test='test(arguments,userDefined)'
tips:子组件中的data
数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如子组件通过ajax
,请求回来的数据,都可以放到data
身上,data
上的数据都是可读可写的;
<h3 id='myh3' ref='myh3'> </h3>
methods:{
getElement(){
console.log( this.$refs.myh3.innerText)
}
}
//组件也可以使用ref,让父组件调用子组件里的方法和属性值
<login ref='mylogin'> </login>
methods:{
getElement(){
//父组件调用子组件里的属性值
console.log(this.$refs.mylogin.msg)
}
}
tips:
refs
; s
代表多个引用,会有多个 dom
元素。ref
英文是 reference
,值类型和引用类型。1、占位符
这是 vue-router
提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view
中去,所以我们可以把 router-view 认为是一个占位符
<router-view></router-view>
2、路由切换模板
路由切换模板写法,默认渲染为一个 a
标签,使用 tag
的 span
可以用来转换模板的标签名
<router-link to="/login" tag='span' >
登录
</router-link>
3、路由配置
new VueRouter({
//路由匹配规则
routes:[
{
path:'/',
redirect:'/login'
},
{
path:'login',
component:login
},
{
path:'/register',
component:register
}
]
//路由高亮的类名
linkActiveClass:'myactive'
})
var vm=new Vue({
el:'#app',
data:{},
methods:{},
router //将路由规则对象注册到vm实例上,用来监听Url地址的变化,然后展示对应的组件。
})
4、路由传参
query
//获取id
this.$route.query.id
path
上设置参数//参数要一一对应不可缺失,不然可能会
造成路由的不匹配
< router-link
to="/login/12/ls"
>
{
path:'/login/:id/:name',component:login
}
params
新的方式可看文档5、子路由
<router-link
to="/account/login"
>
</router-link>
routes:[{ path:'/account', component:account, children:{ { path:'login', component:login } }}]
tips:
path
,表示监听,哪个路由链接地址;component
,表示,如果路由是前面匹配到的 path,则展示 component
属性对应的那个组件。/
, 加了/ 会以根目录为基准匹配,这样不方便我们用户去理解 url
地址to
一定要加上父路由注意: componen
属性值,必须是一个组件的模板对象,不能是组件的引用名称
根据 name
来找组件
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="main"></router-view>
var header={
template:'<h1>header</h1>'
}
var leftBox={
template:'<h1>leftBox</h1>'
}
var mainBox={
template:'<h1>mainBox</h1>'
}
{
path:'/',components:{
'default':header,
'left':leftBox,
'main':mainBox
}
}
监听非 dom
元素
watch:{
'obj.a'(newValue,oldValue){ },
immediate:false
}
watch:{
'obj':{
handler (newValue, oldValue) {
}
},
deep:true //深程度监听 性能消耗大
}
watch:{
//监听路由
'$route.path':{
handler (newValue, oldValue) {
}
},
//immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行
immediate:true
}
tips:
obj.a
加上 handle +immediate:true
,就可以监听 对象里的值,如果是obj
加上 handle+deep true
也是可以监听对象的属性但是性能消耗大 一般是直接对象> > +属性handle
方法可以让 watch
初始化就执行,如果不用 handle 它就先不执行,待数据改变再执行。watch
和 computer
中去修改参与计算或者监听的值 而是要生成新的值。computed:{
'fullname':(){
return
}
}
render:function(createElements){ //createElements是一个方法,调用它,能够把指定的 组件模板 渲染为html结构 return createElements(login) //注意 这里 return 的结果,会替换页面中el 指定的那个容器 }
tips: render
和 components
区别 render
会把整个 app
里组件全部覆盖掉一个 app
中只能放一个 render
组件 components
可以多个,且不会覆盖。
1、写插槽
<div v-if="layout === 'block'" class="layout-block" :class="scroll?'layout-scroll':''">
<slot></slot> //匿名插槽
</div>
<!-- 左右块 -->
<div v-if="layout === 'both'" class="d-flex jc-between">
<div class="layout-both" :class="scrollLeft?'layout-scroll':''">
<slot name="left"></slot> //有名字的插槽
</div>
<div class="layout-both" :class="scrollRight?'layout-scroll':''">
<slot name="right"></slot>
</div>
</div>
2、使用插槽
//有名字的插槽 # v-slot的缩写是#
<template #left></template>
<template v-slot="left" > </template>
tips:区别对待 v-slot="" 和 v-slot:name; = 和 : 的区别 一个是 slot 的 name 一个是父组件获取子组件的数据,插槽一定要用 template 包裹着
<template>
插槽的内容
</template>
2. 杂项
安装 nrm
npm i nrm -g
全局安装nrm ls
显示列表nrm use npm
使用 npm use
后有很多地址可选择tips: nrm
只是单纯的提供几个常用的下载包 url
地址,并能够让我们在这几个地址之前,很方便的进行切换,但是,我们每次装包的时候,使用的装包工具,都是 npm
和 npm i cnpm -g
不一样。
在网页中会引用哪些常见的静态资源
webpack-dev-server
实现自动打包功能,浏览器不用刷新也能看到文件已经修改,打包的文件并没有放在实际的物理磁盘上,而是直接托管到了,电脑的内存中,所以,我们在项目根目录中,根本找不到这个打包好的文件,这文件和 src
、 dist
、 node_modules
平级,有一个看不见的文件。
hot
网页不重载 直接更新 加快打包速度 不生成新文件
"scripts":{
"dev":"webpack-dev-ser ver --open --prot 3000 --contentBase src --hot "
}
配置文件中配置热更新
devServer:{
hot:true 就热更新了
}
tips: webpage
当中带 s
都是数组
在 webpack
中使用以下方式导入的 Vue
构造函数,功能并不完善,只提供了 runtime-only
的方式,并没有提供 像网页中那样的使用方式;
阉割版
import Vue from 'vue'
齐全版
1.
import Vue from '../node_modules/vue/dist/vue.js'
2.
module.exports={
resolve:{
//设置 Vue被导入的时候的包的路径
alias:{
"vue$":"vue/dist/vue.js"
}
}
}
tips: 包的查找规则
node_modules
的文件夹node_modules
中 根据包名,找对应的 vue
文件夹vue
文件夹中,找一个叫做 package.json
的包配置文件package.json
文件中,查找一个 main
属性[ main
属性指定了这个包在被加载时候的入口文件]webpake
的包就需要重新运行项目如果想要通过 vue
,把一个组件放到页面中去展示,vm
实例中的 render
函数可以实现
render:function(createElement){
return createElement(login)
}
//就一行可以省略{} 并且没有花括号默认就有return,
简写: render: c => c(login)
tips: webpack
中如何使用 Vue
Vue
的包webpack
中,推荐使用 .vue
这个组件模板文件定义组件,所以需要安装 能解析这种文件的 loader
main.js
中,导入 vue
模块 import Vue from 'vue'
.vue
结尾的组件,其中,组件有三部分组成import login from './login.vue'
导入这个组件vm
的实例 var vm = new Vue
({el:'app',render:c=>c(login)})
id
为 app
的 div
元素,作为我们 vm 实例要控制的区域export default
向外暴露的成员,可以使用任意的变量来接收export default
只允许向外暴露1次export default
和 export
向外暴露成员export
向外暴露的成员,只能使用{}的形式来接收,这种形式,叫做[按需导出]export
可以向外暴露多个成员,同时,如果某些成员,我们在 import
的时候,不需要,则可以不在 { }中定义export
导出的成员,必须严格按照导出时候的名称,来使用{ } 按需接收 export
导出的成员,如果就想换个名称来接收,可以使用 as 来起别名const arr={
a:'1',
b:'2'
}
export default arr
/* export default {
这个暴露是错误的所以当前注释 一个js文件中只能暴露一次
address:'北京'
}
*/
export title=1
import arr, {title as title1 } from '/xxx.js'
render
会把 el
指定的容器中,所有的内容都清空覆盖,所有不要把路由的router-view
和 router-link
直接写到 el
所控制的元素中app
这个组件,是通过 vm
实例的 render
函数,渲染出来的, render
函数如果要渲染组件,渲染出来的组件,只能放到 el: '#app'
所指定的元素中Account
和 GoodsList
组件,是通过路由匹配监听到的,所以,这两个组件,只能展示到属于路由的 <router-view></router-view>
中去标签页
切换样式的 scoped
是通过 css
的属性选择器来实现的 .aa[vsfp]{color:red}
tips: vsfp 是哈希值
可以映射本地 80
端口,把本地的映射为外网
//npm下载 --感觉下的有点慢 换个路径下比较好
npm install ngrok -g
//命令
ngrok http 80
tips: 需要开启本地服务器,映射后只是映射 www 路径,不是完整的程序路径需要自己去补充完整
//第一种 图片质量小的可以自动转换为base64的
img: require("@/../public/img/home/user.jpg ")
//第二种 这里可以把最前面的 / 看做是public
/img/abnormal/Trash.png
即 public/img/abnormal/Trash.png
tips: @是指 src 目录 .. @ 的上一级目录,再进入 public
3. 性能优化
watch
如果是 obj 加上 handle+deep true
也是可以监听对象的属性但是性能消耗大
computer
里生成的值会有缓存不建议用函数去处理一些值得计算而是用 computer
来计算值,这样性能高。
id 是列表返回的 id 如果没有 id 就写 item 一般不建议写 index (eslint 会有警告错误信息) 写上 key 是为了减少消耗 它会有个缓存。
v-once
和 v-model
的区别是 只会绑定一次 不会重新更新内容 可以 减少开销 应用场景:只读场景,不进行修改页面内容的时候。
可在最外层套用一层 template
来解决
<template v-for="(column, index) in btn">
<el-button size="small"
:type='column.type'
:plain='column.plain'
:class='!isEmpty(column.style)&&[scope.$index + (currentPage - 1) * pageSize==column.style.index?column.style.className:""] '
@click="handle(id&&!column.isGetAll?scope.row[id]:scope.row,column.lable,scope.$index + (currentPage - 1) * pageSize)"
:key='index'>
{{column.lable}}
</el-button>
</template>
this.$parent
可修改父组件值,但不建议,只读就好
vue
配置 在前端生成带有 gz
的文件compression-webpack-plugin
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
const isProduction = process.env.NODE_ENV === 'production'
configureWebpack: config => {
if (isProduction) {
config.plugins.push(
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
)
}
},
ngnix 服务端配置
//配合前端的gzip
在站点配置添加如下代码:
location ~* \.(css|js)$ {
gzip_static on;
}
这是 nginx 的静态 gzip功能,会自动查找对应扩展名的文件,如果存在 gzip 文件,就使用,如果没有就用原文件
//后端返回gzip
gzip on;
gzip_static on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
<script src="https://unpkg.com/vue@2.6.10/dist/vue.runtime.min.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.min.js"></script>
<script src="https://unpkg.com/vue-router@3.0.3/dist/vue-router.min.js"></script>
<script src="https://unpkg.com/axios@0.19.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/element-ui@2.9.2/lib/index.js"></script>
//有了config就按以下配置
configureWebpack: config => {
//cdn
config.externals = {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
axios: 'axios'
}
if (isProduction) {
config.plugins.push(
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
)
}
}
二次
请求;解决方案:
base64
编码 、cdn
requireJs
、也可以使用 webpage
一、建立环境配置文件
在package.json 同级的目录下 建立3个文件
1 .env.development --开发环境 (本地环境)
2 .env.production --正式环境 (正式线服务器--打包)
3 .env.test --测试环境 (测试线服务器--打包)
二、在每个文件中写入具体的配置内容
/*****.env.development文件的内容*****/
NODE_ENV = 'development'
VUE_APP_CURRENT_MODE = 'development'
/*****.env.production文件的内容*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'production'
/*****.env.test*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'test'
三、在package.json 中写入
1.在纯粹的vue_cli3.x配置如下
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build --mode production",
"build:test": "vue-cli-service build --mode test",
},
2.在uni-app下的vue_cli3.x的配置
"scripts": {
"serve": "npm run dev:h5 -- development", //修改点
"build": "npm run build:h5 -- production", //修改点
"build:test": "npm run build:h5 -- test", //修改点
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode", //修改点
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode", //修改点
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js"
},
tips: 以上不同环境的切换,修改点主要就是 mode -- '环境变量'
4. 插件的介绍和使用
配置文件名 postcss.config.js
vue-cli3.x
脚手架自带的 px
转 rem
等单位的配置,建立脚手架的时候选择分离 不然配置在 josn
文件中不好配置
module.exports = {
plugins: [
require('autoprefixer')(),
require('postcss-plugin-px2rem')({
rootValue: 192, //设计图的宽度/10
unitPrecision: 10, //换算的rem保留几位小数点
mediaQuery: true,
minPixelValue: 3
// exclude:/node_modules|folder_name/i,把第三方的框架排除掉
})
]
}
删除 console
,在根目录中新建个 .babelrc
的文件,在以下文件中配置
//第一种
{
"env": {
"production": {
"plugins": [
["transform-remove-console", { "exclude": ["error", "warn"] }]
]
}
}
}
//第二种
一、建立环境配置文件
在package.json 同级的目录下 建立3个文件
1 .env.development --开发环境 (本地环境)
2 .env.production --正式环境 (正式线服务器--打包)
3 .env.test --测试环境 (测试线服务器--打包)
二、在每个文件中写入具体的配置内容
/*****.env.development文件的内容*****/
NODE_ENV = 'development'
VUE_APP_CURRENT_MODE = 'development'
/*****.env.production文件的内容*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'production'
/*****.env.test*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'test'
三、在package.json 中写入
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build --mode production",
"build:test": "vue-cli-service build --mode test",
},
四、在babel.config.js 中写
let transformRemoveConsolePlugin = [];
if (process.env.VUE_APP_CURRENT_MODE === "production") {
transformRemoveConsolePlugin = [
["transform-remove-console", { exclude: ["error", "warn"] }]
];
}
module.exports = {
presets: ["@vue/app"],
plugins: [...transformRemoveConsolePlugin]
};
当使用 html-webpack-plugin
之后,我们不再需要手动处理 bundle.js
的引用路径了,因为这个插件,已经帮我们自动创建了一个合适的script,并且,引用了正确的路径。
/*导入在内存中生成html页面的插件,只要是插件,都一定要放到plugins节点中去
*/
const htmlWebpackPlugin=require("html-webpack-plugin")
//创建一个 内存中 生成html 页面的插件
new htmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html')
filename:'index.html'
})
//这个节点,用于配置 所有 第三方模块 加载器
module:{
rules:[
{test:/\.css$,use:[]}
]
}
构建阶段生成匹配预渲染路径的 html 文件
npm install prerender-spa-plugin --save
vue.config.js
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
configureWebpack: config => {
if (isProduction) {
config.plugins.push(
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
),
config.plugins.push(
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: [
// '/'
'/login'
// '/show',
// '/websocket',
// 'websocket2',
// '/websocket3',
// '/home',
// 'abnormal/AbnormalStatis',
// 'abnormal/FocusCrowd',
// 'abnormal/FocusDetail',
// 'abnormal/ScaleDetail',
// 'abnormal/WarnSetup',
// 'abnormal/WarnDetail',
// 'abnormal/WarnLists',
// 'abnormal/PsychMonth',
// 'abnormal/PsychTeacher',
// 'abnormal/PsychList',
// 'laboratory/sports/MoveClock',
// 'laboratory/sports/ClockDetail',
// 'activity/ActList',
// 'activity/ActForm'
],
minify: {
minifyCSS: true, // css压缩
removeComments: true // 移除注释
},
server: {
port: 8080
},
//忽略打包错误
ignoreJSErrors: true,
phantomOptions: '--web-security=false',
maxAttempts: 10,
renderer: new Renderer({
injectProperty: '__PRERENDER_INJECTED',
inject: {
foo: 'bar'
},
headless: false,
renderAfterTime: 5000,
renderAfterDocumentEvent: 'render-event'
})
})
)
}
},
main.js
new Vue({
mounted() {
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')
tips: main.js
中的render-event
,要和 renderAfterDocumentEvent:'render-event'
一一对应 ,publicPath
目前验证必须是/ 不能自定义文件夹。