前言
当前总结是本人在业余学习与实践过程后的总结与归纳,旨在检验自己的积累,也方便忘记时查阅,同时也希望能帮助那些这方面知识匮乏的同行门,总结是基于 vue2.x
,vue-cli3.x
,主要记录些,vue
常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuex
,vue-router
等日常工作中时常用到的东西,也有些常用的插件
和开发工具
的介绍与使用,以及部分性能优化
的建议与实践,如有不对,或不足的地方,也请各位大神,指出来,学习学习。
目录
1. 基础
1.1 理解mvvm
1.2 常用指令
1.3 常用事件修饰符
1.4 数据的绑定
1.5 class 绑定
1.6 v-for的使用
1.7 v-if、v-show
1.8 调试插件
1.9 全局和私有过滤器
1.10 按键修饰符
1.11 定义指令
1.12 生命周期
1.13 过渡类名实现动画
1.14 组件
1.15 组件里的 data
1.16 组件切换
1.17 父子组件通讯
1.18 使用 ref 获取 dom 元素
1.19 路由
1.20 命名视图实现经典布局
1.21 watch
1.22 computed 计算属性
1.23 render 函数注册组件(vm[vue实例]的属性)
1.24 slot 插槽
2. 杂项
2.1 nrm
2.2 webpack
2.3 热部署
2.4 热更新
2.5 webpack 引入 vue
2.6 在 webpack 中通过 render 展示组件
2.7 export default 和 export
2.8 router
2.9 scoped 原理
2.10 ngrok
2.11 public 目录下的图片如何用 require引入
3. 性能优化
3.1 watch 性能优化
3.2 computer 性能优化
3.3 :key ='id'
3.4 v-once 和 v-model 的区别
3.5 v-for 和 v-if 不适合在同个div连用
3.6 this.$parent
3.7 gzip 优化
3.8 cdn 加速
3.9 网页中引入的静态资源多了以后有什么问题?
3.10 建立不同的环境变量(开发、测试、正式)
4. 插件的介绍和使用
4.1 postcss-plugin-px2rem
4.2 babel-plugin-transform-remove-console
4.3 html-webpack-plugin
4.4 prerender-spa-plugin
1. 基础
▐ 1.1 理解mvvm
m
是vue
实例中的data
,自定义的数据或后端返回的数组不是后端mvc
里的model
概念不同vm
是vue
的实例m
和v
之间的调度者是mvvm
的核心思想v
是html
要渲染的
▐ 1.2 常用指令
v-cloak
解决 {{}} 插值闪烁问题v-text
会先执行 覆盖 元素中原本的内容 但是插值表达式只会覆盖自己的占位符,默认不会闪烁v-html
渲染 html 标签 覆盖元素中原有元素内容v-bind
: 简写为: 用来绑定数据 可以写合法的 js 表达式v-on
: 简写为@
用来点击事件
▐ 1.3 常用事件修饰符
stop
阻止冒泡 :外层和里层都有方法 点击里层会产生冒泡,也会触发外层的事件。顺序 从里到外产生事件prevent
阻止浏览器默认行为 :a
标签有浏览器默认行为。capture
捕获事件 :点击里层先触发外层再触发里层 顺序从外到里产生事件self
只触发自己本身的事件 不会产生冒泡和捕获事件 类似于阻止冒泡 但只针对自己那一层 最外层还是会被最里层冒泡冒到stop
是阻止所有层次once
事件只执行一次
▐ 1.4 数据的绑定
v-bind
: 数据的单向绑定v-modle
:数据的双向绑定 这个只能用于表单元素中
tips: 表单元素 radio
text
address
email
select
checkbox
textarea
▐ 1.5 class 绑定
1、数组带对象
代码语言:javascript复制<div :class="[classA,classB,{'classC':flag}]" >
data(){
return{
flag:true
}
}
tips: 可以在类中的数组中写三元表达式,但推荐使用对象来代替它控制是否渲染
2、单纯的对象
代码语言:javascript复制<div :class="{classA:falg1,classB:flag2}" />
data(){
return{
falg1:true,
falg2:true
}
}
3、数组带三元
代码语言:javascript复制<div :class="['ac','bd',falg?'active','']" / >
data(){
return{
falg:true,
}
}
4、对象升级
代码语言:javascript复制<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}
}
}
▐ 1.6 v-for的使用
可以遍历: 普通数组,对象数组,对象,还可以是数字
代码语言:javascript复制<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
▐ 1.7 v-if、v-show
v-if
有较高的切换性能 , 适合元素可能永远不会被用户看到v-show
有较高的初始渲染消耗,适合元素频繁切换
▐ 1.8 调试插件
- 在谷歌商店找
vue-devtools
插件,使用这个插件并设置插件,允许访问文件网址。会在调试中出现vue相关的东西 debugger
直接写可以调试
▐ 1.9 全局和私有过滤器
代码语言:javascript复制
<div v-for='(item,key) in object' :key='index'>
{{item | dateFormat}}
</div>
<div v-for='(count in 10)'> </div>
全局
代码语言:javascript复制vue.filter('过滤器名称',function(){
})
私有(局部)
代码语言:javascript复制 filters:{
dateFormat:function(data,param){
do some
}
}
tips:
data
就是|
第一个参数已经被定死了,永远是, 管道左边要被转换的数据,param 是过滤方法传进来的其他参数,过滤器采用就近优先原则,如果私有和全局的名称一样就优先采用私有的。padstart
和padend
es6
的补0
方法- 第二个参数是字符串,第三个参数是表达式,如果自己定义参数值是动态的会报错,还未找到原因,后期会找时间再看看,目前就是
简单的过滤用过滤器
,复杂点用方法
,能用计算属性用计算属性
,有缓存,能提高性能
▐ 1.10 按键修饰符
- 监听pc键盘上的值
<input @keyup.enter='方法名'></input>
tips: enter
可以换成键盘上的任何一个值,只要去找相关的键盘码,就都可以使用,推荐设置个别名,放在没有按钮操作的模板。
- 自定义全局按键修饰符
Vue.config.keyCodes.f2=113
, 就可使用了
tips: f2
修饰符是 vue
里没有定义的自己创建。
▐ 1.11 定义指令
1. 全局
定义的指令都要按规定去创建在 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
2. 局部
代码语言:javascript复制directives:{
'指令名':{
bind:function( el,b){
}
}
}
3. 简写
代码语言:javascript复制'指令名':function(el,binding){
} //注意这个function 等同于 把代码写到bind和update中去
tips: 样式相关的指令放在 bind
中,js
行为相关的放在 inserted
中比较合适,防止指令不生效。使用场景 写组件时可以用这个去改样式
▐ 1.12 生命周期
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.13 过渡类名实现动画
1. vue的内置动画
代码语言:javascript复制 <style>
.v-enter,
.v-leave-to{
opacity:0;
transform:translateX(150px) --这东西是位移
}
.v-enter-active,
.v-leave-active{
transition:all 0.4s ease;
}
</style>
代码语言:javascript复制<transition name='my'>
<h3 v-if="flag"></h3>
</transition>
代码语言:javascript复制<script>
data(){
return {
flag:false
}
}
</script>
2. 使用第三方类实现动画
代码语言:javascript复制<transition enter-active-class="bounceIn"
leave-avtive-class="bounceOut" duration='200'
>
<h3 v-if="flag" class="animated" ></h3>
</transition>
3. 在属性中声明js钩子 实现半场动画(只需要进场,不需要离场)
代码语言:javascript复制<transition
<div
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
代码语言:javascript复制<transition
<div
v-show="flag"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
代码语言:javascript复制<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>
代码语言:javascript复制 .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;
}
代码语言:javascript复制<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.14 组件
1.使用Vue.extend 来创建全局的Vue组件
代码语言:javascript复制var coml=Vue.extend({
template:'<h3>这是使用Vue.extend 创建的组件</h3>'
})
代码语言:javascript复制//第一个参数组件名称,第二个参数创建出来的组件模板对象
Vue.component('myComl',coml)
代码语言:javascript复制<my-coml><my-coml/>
2.使用 vue.component 来创建组件
代码语言:javascript复制Vue.component('mycom2',{
template:'<div>
<h3>
这是直接使用Vue.component 创建出来的组件
</h3>
</div>'
})
3.使用 template 来创建组件
代码语言:javascript复制<template id='tmp1'>
<div>
<h1>
这里通过template元素,在外部定义的组件结构,这个方式,有代码的智能提示和高量
</h1>
</div>
</template>
Vue.component('mycom3',{
template:'#tem1'
})
4.私有组件 componment
代码语言:javascript复制<template id='temp2'>
<h1>这是私有login组件</h1>
</template>
componment:{
login:
{
template:'tmpl2'
}
}
- 如果使用了
Vue.component
定义了全局组件的时候,组件名称使用了驼峰命名,在引用的时候大写的驼峰要改为小写,同时两个单词之间 使用-链接 Vue.component
第一个参数:组件的名称,将来在引用组件的时候,就是一个标签形式来引入的,第二个参数:Vue.extend
创建的组件,其中template
就是组件将来要展示的内容- 注意:不论是哪种方式创建出来的组件,组件的
template
属性指向的模板内容,必须有且只能有唯一的一个根元素。
▐ 1.15 组件里的 data
- 组件可以有自己的
data
数据 - 组件的
data
和实例中的data
有点不一样,实例中的data
可以为一个对象,但是组件中的 data 必须是一个方法。 - 组件中的
data
除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行。 - 组件中的
data
数据,使用方式,和实例中的data
使用方式完全一样! - 组件里
data
为什么必须是个方法返回个对象呢?因为要确保每个实例
里的数据是唯一的,独有的。如果data
里的数据是放在实例外部
的,会被其他实例
共享。
▐ 1.16 组件切换
1、组件里的切换 可以用 v-if
和 v-else
进行切换即标签页切换
<a href=""
@click.prevent="flag=true"
>
登录
</a>
代码语言:javascript复制 <a href=""
@click.prevent="flag=flase"
>
注册
</a>
代码语言:javascript复制 <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.17 父子组件通讯
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、在父组件中接收子组件所有参数的同时,添加自定义参数
代码语言:javascript复制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
上的数据都是可读可写的;
▐ 1.18 使用 ref 获取 dom 元素
代码语言:javascript复制
<h3 id='myh3' ref='myh3'> </h3>
methods:{
getElement(){
console.log( this.$refs.myh3.innerText)
}
}
代码语言:javascript复制//组件也可以使用ref,让父组件调用子组件里的方法和属性值
<login ref='mylogin'> </login>
methods:{
getElement(){
//父组件调用子组件里的属性值
console.log(this.$refs.mylogin.msg)
}
}
tips:
refs
;s
代表多个引用,会有多个dom
元素。ref
英文是reference
,值类型和引用类型。
▐ 1.19 路由
1、占位符
这是 vue-router
提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view
中去,所以我们可以把 router-view 认为是一个占位符
<router-view></router-view>
2、路由切换模板
路由切换模板写法,默认渲染为一个 a
标签,使用 tag
的 span
可以用来转换模板的标签名
<router-link to="/login" tag='span' >
登录
</router-link>
3、路由配置
代码语言:javascript复制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"
>
代码语言:javascript复制{
path:'/login/:id/:name',component:login
}
params
新的方式可看文档
5、子路由
代码语言:javascript复制<router-link
to="/account/login"
>
</router-link>
代码语言:javascript复制routes:[{ path:'/account', component:account, children:{ { path:'login', component:login } }}]
tips:
- 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性。
- 属性1 是
path
,表示监听,哪个路由链接地址; - 属性2是
component
,表示,如果路由是前面匹配到的 path,则展示component
属性对应的那个组件。 - 子路由不能加
/
, 加了/ 会以根目录为基准匹配,这样不方便我们用户去理解url
地址 - 超链接的
to
一定要加上父路由
注意: componen
属性值,必须是一个组件的模板对象,不能是组件的引用名称
▐ 1.20 命名视图实现经典布局
根据 name
来找组件
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="main"></router-view>
代码语言:javascript复制var header={
template:'<h1>header</h1>'
}
var leftBox={
template:'<h1>leftBox</h1>'
}
var mainBox={
template:'<h1>mainBox</h1>'
}
代码语言:javascript复制{
path:'/',components:{
'default':header,
'left':leftBox,
'main':mainBox
}
}
▐ 1.21 watch
监听非 dom
元素
watch:{
'obj.a'(newValue,oldValue){ },
immediate:false
}
代码语言:javascript复制 watch:{
'obj':{
handler (newValue, oldValue) {
}
},
deep:true //深程度监听 性能消耗大
}
代码语言:javascript复制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
中去修改参与计算或者监听的值 而是要生成新的值。
▐ 1.22 computed 计算属性
代码语言:javascript复制computed:{
'fullname':(){
return
}
}
▐ 1.23 render 函数注册组件(vm[vue实例]的属性)
代码语言:javascript复制
render:function(createElements){ //createElements是一个方法,调用它,能够把指定的 组件模板 渲染为html结构 return createElements(login) //注意 这里 return 的结果,会替换页面中el 指定的那个容器 }
tips: render
和 components
区别 render
会把整个 app
里组件全部覆盖掉一个 app
中只能放一个 render
组件 components
可以多个,且不会覆盖。
▐ 1.24 slot 插槽
1、写插槽
代码语言:javascript复制 <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、使用插槽
代码语言:javascript复制 //有名字的插槽 # v-slot的缩写是#
<template #left></template>
<template v-slot="left" > </template>
tips:区别对待 v-slot="" 和 v-slot:name; = 和 : 的区别 一个是 slot 的 name 一个是父组件获取子组件的数据,插槽一定要用 template 包裹着
代码语言:javascript复制<template>
插槽的内容
</template>
2. 杂项
▐ 2.1 nrm
安装 nrm
npm i nrm -g
全局安装nrm ls
显示列表nrm use npm
使用npm use
后有很多地址可选择
tips: nrm
只是单纯的提供几个常用的下载包 url
地址,并能够让我们在这几个地址之前,很方便的进行切换,但是,我们每次装包的时候,使用的装包工具,都是 npm
和 npm i cnpm -g
不一样。
▐ 2.2 webpack
在网页中会引用哪些常见的静态资源
- js: .js .jsx .coffee .ts(TypeScript)
- css: .css .less .sass .scss
- Image: .jpg .png .gif .bmp .svg
- 字体文件(Fonts): .svg .ttf .eof .woff .woff2
- 模板文件: .ejs .jade .vue
▐ 2.3 热部署
webpack-dev-server
实现自动打包功能,浏览器不用刷新也能看到文件已经修改,打包的文件并没有放在实际的物理磁盘上,而是直接托管到了,电脑的内存中,所以,我们在项目根目录中,根本找不到这个打包好的文件,这文件和 src
、 dist
、 node_modules
平级,有一个看不见的文件。
▐ 2.4 热更新
hot
网页不重载 直接更新 加快打包速度 不生成新文件
"scripts":{
"dev":"webpack-dev-ser ver --open --prot 3000 --contentBase src --hot "
}
配置文件中配置热更新
代码语言:javascript复制 devServer:{
hot:true 就热更新了
}
tips: webpage
当中带 s
都是数组
▐ 2.5 webpack 引入 vue
在 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
的包就需要重新运行项目
▐ 2.6 在 webpack 中通过 render 展示组件
如果想要通过 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 实例要控制的区域
- 在
▐ 2.7 export default 和 export
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'
▐ 2.8 router
render
会把el
指定的容器中,所有的内容都清空覆盖,所有不要把路由的router-view
和router-link
直接写到el
所控制的元素中- 注意
app
这个组件,是通过vm
实例的render
函数,渲染出来的,render
函数如果要渲染组件,渲染出来的组件,只能放到el: '#app'
所指定的元素中 Account
和GoodsList
组件,是通过路由匹配监听到的,所以,这两个组件,只能展示到属于路由的<router-view></router-view>
中去- 子路由的应用场景在
标签页
切换
▐ 2.9 scoped 原理
样式的 scoped
是通过 css
的属性选择器来实现的 .aa[vsfp]{color:red}
tips: vsfp 是哈希值
▐ 2.10 ngrok
可以映射本地 80
端口,把本地的映射为外网
//npm下载 --感觉下的有点慢 换个路径下比较好
npm install ngrok -g
//命令
ngrok http 80
tips: 需要开启本地服务器,映射后只是映射 www 路径,不是完整的程序路径需要自己去补充完整
▐ 2.11 public 目录下的图片如何用 require引入
代码语言:javascript复制//第一种 图片质量小的可以自动转换为base64的
img: require("@/../public/img/home/user.jpg ")
//第二种 这里可以把最前面的 / 看做是public
/img/abnormal/Trash.png
即 public/img/abnormal/Trash.png
tips: @是指 src 目录 .. @ 的上一级目录,再进入 public
3. 性能优化
▐ 3.1 watch 性能优化
watch
如果是 obj 加上 handle deep true
也是可以监听对象的属性但是性能消耗大
▐ 3.2 computer 性能优化
computer
里生成的值会有缓存不建议用函数去处理一些值得计算而是用 computer
来计算值,这样性能高。
▐ 3.3 :key ='id'
id 是列表返回的 id 如果没有 id 就写 item 一般不建议写 index (eslint 会有警告错误信息) 写上 key 是为了减少消耗 它会有个缓存。
▐ 3.4 v-once 和 v-model 的区别
v-once
和 v-model
的区别是 只会绑定一次 不会重新更新内容 可以 减少开销 应用场景:只读场景,不进行修改页面内容的时候。
▐ 3.5 v-for 和 v-if 不适合在同个div连用
可在最外层套用一层 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>
▐ 3.6 this.$parent
this.$parent
可修改父组件值,但不建议,只读就好
▐ 3.7 gzip 优化
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 服务端配置
代码语言:javascript复制 //配合前端的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].";
▐ 3.8 cdn 加速
代码语言:javascript复制 <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>
代码语言:javascript复制 //有了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
})
)
}
}
▐ 3.9 网页中引入的静态资源多了以后有什么问题?
- 网页加载速度慢, 因为我们要发起很多的
二次
请求; - 要处理错综复杂的依赖关系
解决方案:
- 合并、压缩、精灵图、图片的
base64
编码 、cdn
- 可以使用之前学过的
requireJs
、也可以使用webpage
▐ 3.10 建立不同的环境变量(开发、测试、正式)
代码语言:javascript复制一、建立环境配置文件
在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. 插件的介绍和使用
▐ 4.1 postcss-plugin-px2rem
配置文件名 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,把第三方的框架排除掉
})
]
}
▐ 4.2 babel-plugin-transform-remove-console
删除 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]
};
▐ 4.3 html-webpack-plugin
当使用 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'
})
代码语言:javascript复制//这个节点,用于配置 所有 第三方模块 加载器
module:{
rules:[
{test:/.css$,use:[]}
]
}
▐ 4.4 prerender-spa-plugin
构建阶段生成匹配预渲染路径的 html 文件
代码语言:javascript复制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
目前验证必须是/ 不能自定义文件夹。