实战总结 Vue 学习看这一篇就够了

2021-02-26 15:27:16 浏览数 (1)

前言

当前总结是本人在业余学习与实践过程后的总结与归纳,旨在检验自己的积累,也方便忘记时查阅,同时也希望能帮助那些这方面知识匮乏的同行门,总结是基于 vue2.x,vue-cli3.x ,主要记录些,vue 常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuexvue-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 的对象来实现样式的修改

代码语言:javascript复制
    <div :class="styleObj" />

    data(){
        return{
          styleObj:{color:red}
        }
    }

6、使用 style 的数组带对象来实现样式的修改

代码语言:javascript复制
<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 是过滤方法传进来的其他参数,过滤器采用就近优先原则,如果私有和全局的名称一样就优先采用私有的。
  • padstartpadend es6 的补 0 方法
  • 第二个参数是字符串,第三个参数是表达式,如果自己定义参数值是动态的会报错,还未找到原因,后期会找时间再看看,目前就是简单的过滤用过滤器,复杂点用方法,能用计算属性用计算属性,有缓存,能提高性能
▐ 1.10 按键修饰符
  • 监听pc键盘上的值
代码语言:javascript复制
<input @keyup.enter='方法名'></input>

tips: enter 可以换成键盘上的任何一个值,只要去找相关的键盘码,就都可以使用,推荐设置个别名,放在没有按钮操作的模板。

  • 自定义全局按键修饰符

Vue.config.keyCodes.f2=113, 就可使用了

tips: f2 修饰符是 vue 里没有定义的自己创建。

▐ 1.11 定义指令
1. 全局

定义的指令都要按规定去创建在 bindinserted 还有 updated 中去创建

代码语言:javascript复制
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

代码语言:javascript复制
<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:

  1. v-enter [这是一个时间点] 是进入之前,元素的起始状态,此时还没有开始进入
  2. v-leave-to [这是一个时间点]是动画离开之后,离开的终止状态,此时,元素动画已经结束了
  3. v-enter-active[入场动画的时间段]
  4. v-leave-active[离场动画的时间段]
  5. animated 是个动画库 新版本似乎不需要加入
  6. 使用:duration=200 来表示动画的时间 如果只写一个表示统一配置了开场和离场时间 用 对象可传入c入场和离场 duration="{enter:200,leave:400}"
  7. 添加appear属性,实现页面刚展示出来,入场时候的效果
  8. 通过为transition-group 元素,设置tag属性指定 transition-group 渲染为指定元素,如果不指定tag属性,默认,渲染为span 标签
  9. 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
  1. 组件可以有自己的 data 数据
  2. 组件的 data 和实例中的 data 有点不一样,实例中的 data 可以为一个对象,但是组件中的 data 必须是一个方法。
  3. 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行。
  4. 组件中的 data 数据,使用方式,和实例中的 data 使用方式完全一样!
  5. 组件里 data 为什么必须是个方法返回个对象呢?因为要确保每个实例里的数据是唯一的,独有的。如果 data 里的数据是放在实例外部的,会被其他实例共享。
▐ 1.16 组件切换

1、组件里的切换 可以用 v-ifv-else 进行切换即标签页切换

代码语言:javascript复制
 <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,来展示对应名称的组件

代码语言:javascript复制
//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 简写 @

代码语言:javascript复制
//父组件中
  <component-name 
  :children='children'  //传值
  @handle='show'  //绑定方法
  >
  </component-name>
  
  data(){
    
    return(){
        children:11
    }  
      
  }
  
  methods:{
      
    show(data){
          
      }
  }

3、emit 英文原意: 是触发,调用,发射的意思。 @handle=show 父组件传show方法给子组件。 子组件接收父组件的方法,并用$emit把子组件的值传给父组件

代码语言:javascript复制
 //子组件中
   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:

  1. refs; s 代表多个引用,会有多个 dom 元素。
  2. ref 英文是 reference ,值类型和引用类型。
▐ 1.19 路由

1、占位符

这是 vue-router 提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view 中去,所以我们可以把 router-view 认为是一个占位符

代码语言:javascript复制
<router-view></router-view>

2、路由切换模板

路由切换模板写法,默认渲染为一个 a 标签,使用 tag span 可以用来转换模板的标签名

代码语言:javascript复制
<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
代码语言:javascript复制
//获取id
this.$route.query.id
  • path 上设置参数
代码语言:javascript复制
//参数要一一对应不可缺失,不然可能会
造成路由的不匹配
< 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 来找组件

代码语言:javascript复制
<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 元素

代码语言:javascript复制
 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 它就先不执行,待数据改变再执行。
  • 不要在 watchcomputer 中去修改参与计算或者监听的值 而是要生成新的值。
▐ 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 地址,并能够让我们在这几个地址之前,很方便的进行切换,但是,我们每次装包的时候,使用的装包工具,都是 npmnpm 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 实现自动打包功能,浏览器不用刷新也能看到文件已经修改,打包的文件并没有放在实际的物理磁盘上,而是直接托管到了,电脑的内存中,所以,我们在项目根目录中,根本找不到这个打包好的文件,这文件和 srcdistnode_modules 平级,有一个看不见的文件。

▐ 2.4 热更新

hot 网页不重载 直接更新 加快打包速度 不生成新文件

代码语言:javascript复制
 "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 的方式,并没有提供 像网页中那样的使用方式;

代码语言:javascript复制
阉割版
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 函数可以实现

代码语言:javascript复制
  render:function(createElement){
     return  createElement(login) 
  }
  
  //就一行可以省略{} 并且没有花括号默认就有return, 
  简写: render: c => c(login)

tips: webpack 中如何使用 Vue

  • 安装 Vue 的包
  • 由于在 webpack 中,推荐使用 .vue 这个组件模板文件定义组件,所以需要安装 能解析这种文件的 loader
    1. main.js 中,导入 vue 模块 import Vue from 'vue'
    2. 定义一个.vue 结尾的组件,其中,组件有三部分组成
    3. 使用 import login from './login.vue' 导入这个组件
    4. 创建 vm 的实例 var vm = new Vue ({el:'app',render:c=>c(login)})
    5. 在页面中创建一个 id app div 元素,作为我们 vm 实例要控制的区域
▐ 2.7 export default 和 export
  • export default 向外暴露的成员,可以使用任意的变量来接收
  • 在一个模块中,export default只允许向外暴露1次
  • 在一个模块中,可以同时使用 export defaultexport 向外暴露成员
  • 使用 export 向外暴露的成员,只能使用{}的形式来接收,这种形式,叫做[按需导出]
  • export 可以向外暴露多个成员,同时,如果某些成员,我们在 import 的时候,不需要,则可以不在 { }中定义
  • 注意使用 export 导出的成员,必须严格按照导出时候的名称,来使用{ } 按需接收
  • 使用 export 导出的成员,如果就想换个名称来接收,可以使用 as 来起别名
代码语言:javascript复制
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' 所指定的元素中
  • AccountGoodsList 组件,是通过路由匹配监听到的,所以,这两个组件,只能展示到属于路由的 <router-view></router-view> 中去
  • 子路由的应用场景在标签页切换
▐ 2.9 scoped 原理

样式的 scoped 是通过 css 的属性选择器来实现的 .aa[vsfp]{color:red}

tips: vsfp 是哈希值

▐ 2.10 ngrok

可以映射本地 80 端口,把本地的映射为外网

代码语言:javascript复制
//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-oncev-model 的区别是 只会绑定一次 不会重新更新内容 可以 减少开销 应用场景:只读场景,不进行修改页面内容的时候。

▐ 3.5 v-for 和 v-if 不适合在同个div连用

可在最外层套用一层 template 来解决

代码语言:javascript复制
    <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
代码语言:javascript复制
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 网页中引入的静态资源多了以后有什么问题?
  • 网页加载速度慢, 因为我们要发起很多的二次请求;
  • 要处理错综复杂的依赖关系

解决方案:

  1. 合并、压缩、精灵图、图片的 base64 编码 、cdn
  2. 可以使用之前学过的 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 文件中不好配置

代码语言:javascript复制
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 的文件,在以下文件中配置

代码语言:javascript复制
//第一种
{
  "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,并且,引用了正确的路径。

代码语言:javascript复制
/*导入在内存中生成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 目前验证必须是/ 不能自定义文件夹。

0 人点赞