8

前言

    当前总结是本人在业余学习与实践过程后的总结与归纳,旨在检验自己的积累,也方便忘记时查阅,同时也希望能帮助那些这方面知识匮乏的同行门,总结是基于vue2.x,vue-cli3.x,主要记录些,vue常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuexvue-router等日常工作中时常用到的东西,也有些常用的插件开发工具的介绍与使用,以及部分性能优化的建议与实践,如有不对,或不足的地方,也请各位大神,指出来,学习学习。

1.基础

1. 理解mvvm
  • mvue实例中的data,自定义的数据或后端返回的数组

不是后端mvc里的model概念不同。

  • vmvue的实例 mv之间的调度者 是mvvm的核心思想
  • vhtml 要渲染的。
2. 常用指令
  • v-cloak 解决{{}}插值闪烁问题
  • v-text 会先执行 覆盖 元素中原本的内容 但是插值表达式只会覆盖自己的占位符,默认不会闪烁
  • v-html 渲染 html标签 覆盖元素中原有元素内容
  • v-bind: 简写为: 用来绑定数据 可以写合法的js表达式
  • v-on: 简写为 @ 用来点击事件
3.常用事件修饰符
  • stop 阻止冒泡 :外层和里层都有方法 点击里层会产生冒泡,也会触发外层的事件。顺序 从里到外产生事件
  • prevent 阻止浏览器默认行为 :a标签有浏览器默认行为。
  • capture 捕获事件 :点击里层先触发外层再触发里层 顺序从外到里产生事件
  • self 只触发自己本身的事件 不会产生冒泡和捕获事件 类似于阻止冒泡 但只针对自己那一层 最外层还是会被最里层冒泡冒到 stop 是阻止所有层次
  • once 事件只执行一次
4.数据的绑定
  • v-bind: 数据的单向绑定
  • v-modle :数据的双向绑定 这个只能用于表单元素中
tips: 表单元素 radio text address email select checkbox textarea
5.class 绑定
  • 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}
    }
}
6.v-for的使用

可以遍历: 普通数组,对象数组,对象,还可以是数字

<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
7.v-ifv-show
  • v-if 有较高的切换性能 , 适合元素可能永远不会被用户看到。
  • v-show 有较高的初始渲染消耗,适合元素频繁切换。
8 调试插件
  • 在谷歌商店找vue-devtools插件,使用这个插件

并设置插件,允许访问文件网址。 会在调试中出现vue相关的东西

  • debugger 直接写可以调试
9 过滤器
全局和私有过滤器
<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 是过滤方法传进来的其他参数,过滤器采用就近优先原则,如果私有和全局的名称一样就优先采用私有的。
  • padstartpadend es6 的补0 方法
  • 第二个参数是字符串,第三个参数是表达式,如果自己定义参数值是动态的会报错,还未找到原因,后期会找时间再看看,目前就是简单的过滤用过滤器,复杂点用方法,能用计算属性用计算属性,有缓存,能提高性能
10 按键修饰符
  • 监听pc键盘上的值
<input @keyup.enter='方法名'></input>
tips: enter 可以换成键盘上的任何一个值,只要去找相关的键盘码,就都可以使用,推荐设置个别名,放在没有按钮操作的模板。
  • 自定义全局按键修饰符

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

tips: f2修饰符是vue里没有定义的自己创建。
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. 局部
directives:{
    '指令名':{
     bind:function( el,b){

     }
   }
 }
3. 简写
'指令名':function(el,binding){
    
} //注意这个function 等同于 把代码写到bind和update中去
tips: 样式相关的指令放在bind中,js行为相关的放在inserted中比较合适,防止指令不生效。使用场景 写组件时可以用这个去改样式
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 :

当执行这个函数的时候,组件已经被完全销毁了,此时,组件中所有的数据,方法,指令,过滤器...都已经不可用了

13 过渡类名实现动画
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:

  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属性值。

14 组件

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 属性指向的模板内容,必须有且只能有唯一的一个根元素。
15 组件里的data
  1. 组件可以有自己的data数据
  2. 组件的data和实例中的data有点不一样,实例中的data 可以为一个对象,但是组件中的data必须是一个方法。
  3. 组件中的data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行。
  4. 组件中的data数据,使用方式,和实例中的data使用方式完全一样!
  5. 组件里data为什么必须是个方法返回个对象呢? 因为要确保每个实例里的数据是唯一的,独有的。如果data里的数据是放在实例外部的,会被其他实例共享。
16 组件切换
  1. 组件里的切换 可以用 v-ifv-else 进行切换即标签页切换
 <a href=""
 @click.prevent="flag=true"
 >
 登录
 </a>
 <a href=""
   @click.prevent="flag=flase"
  >
 注册
 </a>
<login v-if="flag">
</login>

<register v-else="flag">
</register>

2.vue 提供了 component,来展示对应名称的组件

//component 是一个占位符

:is属性,可以用来指定要展示的组件的名称 写死的时候这个组件名要是个字符串,动态绑定时key普通写法就好,但value必须是字符串。

<component :is="'componentId'">
</component>

<component :is="oneName">
</component>

data(){
    return{
     oneName:"login",
    }
}
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.在父组件中接收子组件所有参数的同时,添加自定义参数

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 上的数据都是可读可写的;
18 使用 ref 获取dom元素
 <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:

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

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

<router-view></router-view>

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

<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.路由传参
1.query

//获取id
this.$route.query.id 

2.在path上设置参数

//参数要一一对应不可缺失,不然可能会
造成路由的不匹配
< router-link
  to="/login/12/ls"
>
{
    path:'/login/:id/:name',component:login   
}

3.params 新的方式可看文档

5.子路由

<router-link
to="/account/login"
>
</router-link>
routes:[
{
  path:'/account',
  component:account,
  children:{
   {
   path:'login',
   component:login
   }   
  }
}

] 

tips:

  • 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性。
  • 属性1 是path,表示监听,哪个路由链接地址;
  • 属性2是component,表示,如果路由是前面匹配到的path,则展示component属性对应的那个组件。
  • 子路由不能加/, 加了/ 会以根目录为基准匹配,这样不方便我们用户去理解url地址
  • 超链接的to 一定要加上父路由

==注意==:componen属性值,必须是一个组件的模板对象,不能是组件的引用名称

20.命名视图实现经典布局

根据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
    }
}
21.watch

监听非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它就先不执行,待数据改变再执行。
  • 不要在watchcomputer 中去修改参与计算或者监听的值 而是要生成新的值。
22. computed 计算属性
computed:{
 'fullname':(){
  return 
 }
}
23. render 函数注册组件(vm[vue实例]的属性)
 render:function(createElements){
 //createElements是一个方法,调用它,能够把指定的 组件模板 渲染为html结构
  return createElements(login)
  //注意 这里 return 的结果,会替换页面中el 指定的那个容器
 }
tips: rendercomponents区别 render 会把整个app里组件全部覆盖掉一个app中只能放一个render组件components 可以多个,且不会覆盖
24. slot 插槽

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.杂项

1. nrm

安装 nrm

  • npm i nrm -g 全局安装
  • nrm ls 显示列表
  • nrm use npm 使用npm use 后有很多地址可选择
tips:nrm只是单纯的提供几个常用的下载包url地址,并能够让我们在这几个地址之前,很方便的进行切换,但是,我们每次装包的时候,使用的装包工具,都是npm。和
npm i cnpm -g  不一样
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
3. 热部署

webpack-dev-server 实现自动打包功能,浏览器不用刷新也能看到文件已经修改,打包的文件并没有放在实际的物理磁盘上,而是直接托管到了,电脑的内存中,所以,我们在项目根目录中,根本找不到这个打包好的文件,这文件和srcdistnode_modules 平级,有一个看不见的文件

4. 热更新

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

 "scripts":{
   "dev":"webpack-dev-ser  ver --open --prot       3000 --contentBase src --hot "     
 }

配置文件中配置热更新

   devServer:{
     hot:true 就热更新了
}
tips:webpage当中带s都是数组
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的包就需要重新运行项目
6.在webpack中通过render展示组件

如果想要通过vue,把一个组件放到页面中去展示,vm 实例中的render函数可以实现

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

tips: webpack中 如何使用Vue:

  1. 安装Vue的包
  2. 由于在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. 在页面中创建一个idappdiv元素,作为我们vm实例要控制的区域
7. export defaultexport
  • export default 向外暴露的成员,可以使用任意的变量来接收
  • 在一个模块中,export default只允许向外暴露1次
  • 在一个模块中,可以同时使用 export defaultexport 向外暴露成员
  • 使用 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'
     
8. router
  • render会把el指定的容器中,所有的内容都清空覆盖,所有不要把路由的router-viewrouter-link 直接写到el所控制的元素中
  • 注意 app这个组件,是通过vm 实例的render 函数,渲染出来的,render函数如果要渲染组件,渲染出来的组件,只能放到el: '#app'所指定的元素中;
  • AccountGoodsList 组件,是通过路由匹配监听到的,所以,这两个组件,只能展示到属于路由的

    <router-view></router-view>中去
  • 子路由的应用场景在标签页切换
9. scoped原理

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

tips:vsfp是哈希值
10. promise
  • 模拟 promise

     getFution(aa,callback){
      callback(aa)   
    }
    
     getFution(aa,funtion(res){
      console.log (aa)
     })
  • 异步操作

    /*
    每当new一个Promise实例的时候,就会立即执行这个异步操作中的代码。也就是说,new的时候,除了能够得到一个promise实例之外,还会立即调用 我们为 Promise 构造函数传递的那个funtion,执行这个function中的异步操作代码。

*/
var promise=new Promise(function(resolve,reject){

 异步操作,ajax函数等,而且可以自由输出东西了
 resolve(true) 
 reject(false)

})

getFunction(){

var promise=new  Promise(function(){
 异步操作,ajax函数等,而且可以自由输出东西了
 })

}

getFunction().then(
function(data){

console.log(err)

},function(err){

 console.log(err)

})


正确使用方式

getFunction(aa)
.then(function(data){

 console.log(data)
 return getFunction() --返回后,可以使用后续的then

})

.then(function(data){

   console.log(data)
   return getFunction()

})
.then(funtion(data){

  console.log(data)

})
//捕获只放在最后面。前面有任何的异常都会终止

.catch(function(data){
   console.log(data)    
}

 > tips:在 `then`里面多写个返回错误的方法是不可取的。

 #### 11. vuex
 
 + `vuex`是为了保存组件之间共享数据而诞生的,如果组件之间 有要共享的数据,可以直接挂载到`vuex`中,而不必通过父子组件之间传值了,如果组件的数据不需要共享,此时,这些不需要共享的私有数据,没有必要放到`vuex`中;

+ `vuex`,存放共享数据,`data` 存放组件私有的数据 `props`存放父组件传过来的数据

+ 操作`vuex`里的`state`
- 直接操作`store`里的属性值,不推荐这种做法
 this.$store.state.属性值
 ```
    • 推荐只通过mutations 提供的方法,才能操作对应的数据,

        mutations:{
         increment(state,payload){
             state.count++ 
           }
          }
      this.$store.commit('方法名')
    • vuex里的getters

      如果`store`中`state`上的数据,在对外提供的时候,需要做一层包装,那么推荐使用`getters`。
      
      ```
      optCount:state=>state.count
      this.$store.getters.***
      ```
      tips: increment方法里的 state是属于vuex里的state; countstate里的属性 ;payload外部传进来的值,用来修改state里属性的值.。最多支持只能传两个参数,可以是数组和对象。

      #### 12. ngrok
      可以映射本地80端口,把本地的映射为外网
      npm地址

      //npm下载 --感觉下的有点慢 换个路径下比较好
       npm install ngrok -g 
      //命令
       ngrok http 80
      tips: 需要开启本地服务器,映射后只是映射www路径,不是完整的程序路径需要自己去补充完整
    13.public 目录下的图片如何用 require引入
    //第一种 图片质量小的可以自动转换为base64的
    img: require("@/../public/img/home/user.jpg ")
    
    //第二种 这里可以把最前面的 / 看做是public
    /img/abnormal/Trash.png 
    
    即 public/img/abnormal/Trash.png
    
    tips: @是指src目录 .. @的上一级目录,再进入public

    3.性能优化建议

    1.watch如果是obj 加上 handle+deep true 也是可以监听对象的属性但是性能消耗大
    2.computer 里生成的值 会有缓存 不建议用函数去处理一些值得计算 而是用 computer 来计算值,这样性能高。
    3.:key ='id'
    id是列表返回的id 如果没有id 就写item 一般不建议 写 index (eslint会有警告错误信息) 写上key 是为了减少消耗 它会有个缓存。

    4.v-oncev-model 的区别是 只会绑定一次 不会重新更新内容 可以 减少开销 应用场景:只读场景,不进行修改页面内容的时候

    5.v-forv-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>
    

    6.this.$parent 可修改父组件值,但不建议,只读就好

    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服务端配置

     //配合前端的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]\.";
    

    8.cdn加速

        <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
            })
          )
        }
      }

    9.网页中引入的静态资源多了以后有什么问题?

    • 网页加载速度慢, 因为我们要发起很多的二次请求;
    • 要处理错综复杂的依赖关系

      解决方案:
    1. 合并、压缩、精灵图、图片的base64编码 、cdn
    2. 可以使用之前学过的requireJs、也可以使用webpage

    10.建立不同的环境变量(开发、测试、正式)

    一、建立环境配置文件
    在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. 各种插件的介绍和引用

    1.postcss-plugin-px2rem
    配置文件名postcss.config.js vue-cli3.x脚手架自带的pxrem等单位的配置,建立脚手架的时候选择分离 不然配置在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,把第三方的框架排除掉
        })
      ]
    }

    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]
    };
    

    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'
     })
    
    //这个节点,用于配置 所有 第三方模块 加载器
    module:{
      rules:[
       {test:/\.css$,use:[]}
      ]     
    }

    4.prerender-spa-plugin

    构建阶段生成匹配预渲染路径的 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 目前验证必须是/ 不能自定义文件夹
    未完待续~~~

    yaoxfly
    431 声望28 粉丝