vue面试题

VUE

  • Vue :数据驱动的M V Vm框架

  • m :model(后台提供数据),v :view(页面),vM(模板)

  • 流程

    • m-》vm-》v
    • m与vm之间通过ajax axios实现数据交互(前后端数据交互)
    • vm(前端拿到数据后,对数据进行处理)
    • v(数据改变后,页面改变)
  • 兼容

    • ie9及其以上(Vue使用Es5)
    • ie8用的是es3
  • 注意

    • 不要将body、html作为挂载点
    • 新建一个div作为挂载点
    • 一个页面中尽量只有一个挂载点
    • 插值等同{{}}{{}},只能与标签内使用)
    • 等同于innerHTML,innerTEXT
    • 慎用innerHTML(会执行之内的代码->xxs攻击)
    • 指令需要放在标签的属性中使用
    • 指令中的双引号会提供一个js运行环境("变量、简单运算")双大括号{{}}具有相同的功能
    • v-text插入的变量作为字符串处理
    • v-html除非是信任的内容不然不要使用
  • v-show控制元素的显示隐藏

    • 初始开销较大,dom一直存在与结构中 如果是需要经常切换的dom 推荐使用该指令
    • v-show只是css级别的显示隐藏=》display:none
    • 在vue中想要显示或隐藏
      • 给data中添加一个属性,其值为布尔类型
      • 将对应值添加个v-show指令
      • 控制这个布尔值,以达到控制显示隐藏的目的
      • true==显示,flse==隐藏
  • v-if

    • 切换开销较大 false情况下 dom不会被渲染
    • v-if是html结构级别的隐藏,直接将对应标签删除
    • v-if、v-else-if、v-else和js中的if else else if一样的(只能满足一级要求,其后不再执行)
  • v-for

    • 用于遍历数组或对象
    • v-for="item in items"
    • v-for="item,index in items" 项+索引 数组
    • v-for="value in items" 值 对象
    • v-for="value,key in items" 键+值 对象
    • v-for="value,key,index in items" 键+值+索引 对象
    • v-for="自定义名字 数组名"
    • v-for可以遍历出index
    • 对象遍历(不常用)
      • v-for="value in 对象名"
      • v-for="(value,key) in 对象名"
      • v-for="(value,key,index) in 对象名"
    • 要遍历那个标签就将指令写给那个标签
    • 建议所有使用v-for指令的标签都添加上:key="惟一值"(后期使用,不建议使用index(虽然也是唯一的))
    • key vue渲染原理 复用元素 没有key的话 当数据顺序发生变化时 如果没有绑定key 只会更新数据(元素不会更新,dom复用)
    • 不建议同时使用v-for和v-if v-for拥有更高的优先级
  • v-bind:绑定

    • 根据数据改变标签的属性(src,href)
    • 将标签的属性与data中的变量绑定
    • v-bind:src="data中的变量名"(将src与data中对应的变量名绑定,当数据改变时,src中的值也随之改变)
    • 使用非常广泛=》简写成为:属性名="data中的变量"
    • 如果要修改标签中的所有属性,可以绑定data中的对象,对象中的属性名,与标签中的属性一一对应(也可以添加其他属性)(可以更方便快捷的改变标签中的多个属性,或添加属性)
    • :style=""->改变标签css样式
      • 阔以是对象,但是值必须加引号(指令双引号间为js执行环境)
    • :class=""->添加类名
      • :class="[box,box1,{box2:flag}]"
      • :class="{class:flag}"
      • 绑定类名可以与普通class属性共存
        • <span class="class1" :class="{class2:flag1}"></span>
  • v-model:双向绑定

    • 上述方法只能实现,数据改变之后,页面内容随之改变,但数据不会在页面内容改变之后随之改变(即单项绑定)
    • 页面内容改变是(form表单元素),Vue数据改变
      <input type="radio" v-model="" v-bind:value="0">
    
    • 将input中的值value绑定为数字0,(指令中的双引号间为js运行环境),再将input与Vue中的数据,双向绑定,其后可以得到值为数字Number类型
  • v-on:绑定事件

    • v-on后跟事件名,等于函数名(methods对象中的方法),有实参加括号,无实参可省略括号
    • 可以通过this.data中的属性名,获取对应的数据
    • v-on:click="",双引号中可直接对data中的数据进行修改
    • v-on:click="methods方法名",由于使用较多,所以向v-bind一样具有缩写,@click="函数名(实参)"
  • 修饰符

    • v-on:click="methods中的方法名"==@click="methods中的方法名"
    • 事件触发具有冒泡机制,如何禁止-》修饰符
    • @click.stop=""=>阻止冒泡
    • @click.prevent=""=>阻止浏览器默认行为

三了解

  • v-pre:跳过标签编译过程,提升性能

    `<pre>`
      内部代码
      回车
      浏览器编译后
      就是回车
    `</pre>`
    
  • v-clock

    ```<style>
      [v-clock] {
        display:none
      }
    </style>
    ```
    
    • 加载完成之前,具有v-clock的标签隐藏
    • Vue编译完成之后,自动清楚v-clock
  • v-once

    • 只在页面第一次渲染是调用数据
    • 之后不会在跟随数据发生变化

生命周期

四大生命周期

  • 顺序(钩子函数的执行顺序,与data同级)
    • 创建-create
      • beforeCreate:创建前(无data中的数据,只有该阶段无法访问到data中的数据)(数据于创建完成之后进行初始化)
      • created:创建完成后
    • 挂载-mount(app.$mount(""))(不用el:"#app"挂载的话,可以用$mount挂载)
      • beforeMount:挂载之前
      • mounted:挂载之后
    • 更新-update(数据发生改变)
      • beforeUpdate:更新之前
      • updated:更新之后
    • 销毁-destroy
      • beforeDestroy:销毁之前(app.$destroy()强制销毁)
      • destroyed:销毁之后
  • 注意
    • 创建和挂载的四个钩子函数只会调用一次
    • 更新周期对应的两个钩子函数,只要数据发生改变就会触发
  • data
    • vue中的数据时响应式的 所以需要在初始化Vue是将需要响应的变量提前声明
  • Object.freeze()
    • 属性放进去,vue不会对其进行追踪变化了
  • v-once
    • 执行一次性的插值 数据改变时,插值处的内容不在更行

计算属性-computed(对象与data同级)

  • 当遇到比较复杂的语句时,可将其写在computed中
  • computed中的函数不可以调用,而是将其函数名写在{{中}},将其作为data中的属性名
  • 创建时与methods一致,用法与data中的数据一致,对象!!!!
  • 实质:将computed计算的结果return到页面中**
  • 当多次调用同一个computed方法时,会存在缓存问题**,当需要实时更新数据时,可以使用methods(避免缓存)

监听-watch(对象与data同级)

  • watch:{要监听的值的名字(){},要监听的值的名字:{handler(){},deep:true,//可以监听对象内部属性的改变 immediate:true//页面加载后立马执行第一次监听函数}}
  data:{

  },
  watch:{
    //第一种方法(无法监听到对象内部数据变化)
    msg(newValue,oldValue){
      //data中的属性名+()+{},如果msg是对象的话,无法监听对象内属性的变化
      //监听函数有两个参数,分别为新值和旧值
      console.log(newValue,oldValue)
      //该方法无法监听到对象中的数据,只能在变量内存储的地址发生改变时触发(引用类型,栈中存放的是指针,堆中的地址)
    }
    //第二种方法(第一种方法的变形)
    msg:{
      handler(newValue,oldValue){
        console.log(newValue,oldValue)//data中的非对象数据,能够监听变化,并且存在两个数据,即新数据,旧数据
        //仍然监听不到对象中数据的变化
      }
    }
    //第三种方法(添加对应参数)
    msg:{
      handler(){
        console.log("发生了变化")
      },
      deep:true,  //是否监听对象内部数据的变化
      immediate:true  //是否与数据初始化之前设置监听函数
    }
  }
  (详见)[https://cn.vuejs.org/v2/guide/list.html]
  /* 
    由于 JavaScript 的限制,Vue 不能检测以下数组的变动:

    当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
    当你修改数组的长度时,例如:vm.items.length = newLength
    ----vm.items[indexOfItem] = newValue
    // Vue.set
      Vue.set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
      vm.items.splice(indexOfItem, 1, newValue)
    
    Vue 不能检测对象属性的添加或删除
      
   */

过滤器-filters(对象,data同级)

过滤器的应用范围

  • 双花括号插值和v-bind表达式
  • 过滤器的作用是,对对应的值进行处理-{{数据 | 过滤器名}}
  • v-bind可以添加{{可以添加}}v-text不可以添加
  • 过滤器函数中的参数就是 | 之前的对应的数据,过滤器函数中需要返回新的内容才能显示在页面中(即,过滤器函数中需要存在return)
  • 过滤器可以用多个{{数据 | 过滤器1 | 过滤器2 | 过滤器n}}--(过滤器的添加顺序不同(对数据的处理顺序不同,可能造成,处理后数据结果不同))

组件

  • 创建
    • complate组件模板
    • vue组件分为两种,一种为全局组件,一种为局部组件,组件需要注册才能使用
    • 注册:Vue.component("组件名",组件配置对象)---》一般将 组件配置对象提取出来,外部配置
  • 使用组件
    • 要在父组件的组件模板中使用对应的组件标签
    • <组件名></组件名>
  • 局部注册
    • 局部注册需要在对应组件中添加components属性
    const 组件名={
      template:"",
      components:{
        局部组件名:组件配置对象//这个组件就只能在当前组件的模板中使用
        //相当与在对应父元素组件中实现注册,为局部组件,只能在该组件中调用,否则报错
      }
    }
  • 注意
    • 组件模板中只能有一个根节点
    • 组建的配置对象,一定、一定、一定要放在其注册之前
    • 组件中可以写出el对象外的几乎所有属性
    • 组件中的data为函数,需要将数据return出去,然后可以正常使用,其他无异常
    • 可以通过将组件标签,添加到其父组件的complate中,实现
    • 往组件中添加数据,只能在其对应的complate中添加,在html结构标签中无法添加内容&&将其添加到其父元素的complate中后无法修改其数据
    • 因为HTML不区分大小写,所以在HTMl模板中,标签需要写成纯小写,驼峰命名变成-连字符连接

通信方式

  • 父子通信

    • 父->子
      • 父子组件通信基本步骤

        1. 在子组件中添加props(对象)
          配置对应prop的名字
        2. 找到对应父组件模板中的子组件标签
          在标签上添加对应prop的名字作为属性 后边跟着要传递的值

        第二步可以传递静态值(固定值) 也可以传递动态值,data中的值
        区别就在于加不加v-bind

        • 注意
          • props:["prop名1","prop名2",……]---》第一种写法,可以有多个prop,即数据通路

          • props:{prop名字:String}/props:{prop名字:[String,Number]}-->即允许传输的数据类型,可以有多个

          • props:

            {prop名字:{type:允许类型,default:默认值,validator(value){验证数据,true//验证通过,否则报错},required:true}}---->type(允许传输的数据类型),default(无传输数据时的默认值),validator(验证传输数据是否满足条件),required:true(true,则该项为必须传输项目)(与default有冲突,有默认项时,即使无数据传输,默认值将作为数据,是否必填无关紧要)
            
      • props中的prop名,可以直接当做data中属性(数据)使用

      • 遍历数组时,需要添加:key="惟一值即可"

    • 子->父
  • 非父子通信

    main.js中 空vue载体
    Vue.prototype.$bus=new Vue()
        在所有的 Vue 实例中可用了,甚至在实例被创建之前就可以
         $ 是在 Vue 所有实例中都可用的属性的一个简单约定。这样做会避免和已被定义的数据、方法、计算属性产生冲突。
         通过 $ 为实例属性设置作用域来避免这种事情发生。你还可以根据你的喜好使用自己的约定,诸如 $_appName 或 ΩappName,来避免和插件或未来的插件相冲突。
    
     需要进行通信的组件
     import $bus from '../../../main';
    
     this.$bus.$on('upload',payload=>{ do somthing })  //先监听
    
     this.$bus.$emit('getPayload',payload)  //后触发
    

修饰符

  • 事件修饰符,为v-on提供了事件修饰符
    • stop
      • 阻止冒泡
    • prevent
      • 阻止默认行为
    • capture
      • 捕获阶段执行??
    • self
      • event.target 当前元素自身触发时执行函数
    • once
      • 只执行一次
    • passive
      • addEventListener(type,handler,useCapture)-->addEventListener(type,handler,{capture:false,passive:false,once:false})-->是否捕获,是否'顺从'???,是否只执行一次监听(之后自动removeEventListener)
      • passive提高流畅性能
      • 调用preventDefault()无效
  • 按键修饰符,为v-on在监听键盘事件时添加按键修饰符
    • enter .13
    • tab
    • delete
    • esc
    • space
    • up
    • down
    • left
    • right
    • 可以通过全局config.keyCode对象自定义按键修饰符别名
  • 系统修饰键,尽在按下相应按键时才触发鼠标或键盘事件的监听器
    • ctrl
    • alt
    • shift
    • meta
  • exact修饰符允许你控制由精确的系统修饰符组合出发的事件,ctrl+shift等组合键
  • 鼠标按钮修饰符
    • left
    • right
    • middle

路由router

  • 前后端都能够实现根据url的不同,跳转至指定页面,但实现原理不同
  • 四步骤
    • 一 创建组件配置对象
    • 二 创建routes配置对象(必须是routes,否则虽然不报错,但是也不会有效果)
    • 三 创建router实例(new VueRouter)
    • 四 将router添加进Vue中
  • <router-view></router-view>(url对应的组件,将替换掉该组件,即该组件不会显示到页面中)
    • <router-link to="/" tag="li">,该标签渲染到页面中时会被a标签替换,to中将会是替换后的url,tag可以改变渲染后router-link的结果(可以改变成为其他标签,通过js实现相应的链接跳转),激活状态的链接会具有router-link-active(该类名不够精确)---》推荐使用router-link-exact-active来为激活状态的标签添加对应的类名
    • linkExactActiveClass:'active',通过该全局配置,实现类名的替换var router=new VueRouter({//new VueRouter大括号中为全局配置 linkExactActiveClass})
    • 点击对应router-link标签,to到新的url后,显示对应的组件,实现页面的跳转(数据的改变)但域名不会改变

动态路由

    1. 配置路由时可以使用动态路由{path:"/a/:id"}
    • 通过$route.params.id来获取对应的id,根据id获取数据,并改变显示内容
    • 通过为$route设置监听函数,来实现当url改变时,发送新的请求,获取数据后渲染到页面的操作,可以为其添加immediate属性,实现页面首次加载就发出请求
    • 如果动态路由想要使用a标签跳转,必须给路由添加一个name属性并使用名字进行跳转
      • <router-link :to="{path: '/demo', params: {id: 1}}">链接</router-link>
    1. 使用?id=xx的形式--query
    • 配置路由时使用基本配置方式
    • 将query值添加到路由的最后使用?xx=值的形式添加?xx=值&xx=值
    • 通过$route.query.xx来获取

动态路由与静态路由的区别

  • 二者无实质区别(都是根据url不同,获取数据渲染到页面中)
  • 获取方式的差别
    • 动态路由获取--$route.params.xxx与配置对象中routes[{path:"/:xxx"}]--只需要xxx一致即可---当使用router-link :to="{name:'',params:{xxx:''}",只需要v-bind:to即可,否则获取到的是字符串--(需要使用name)
    • 静态路由--$route.query.xxx与链接中router-link to="/?xxx=xx"

原理

  • 通过切换url,获取数据,更换div中的内容
  • 后端为主--原始模式
    1. 查找dns服务器,dns服务器返回对应的ip地址
    2. 根据ip地址找到服务器
    3. 服务器后台根据url提取数据
    4. 根据提取的数据去数据库中查找数据
    5. 将数据渲染到模板中的页面
    6. 返回浏览器
    • 前端只负责提供静态页面模板,供后端渲染数据
  • 前端为主--Vue--M、V、VM
    1. 查找 dns服务器,dns服务器返回对应的ip地址
    2. 根据ip地址找到服务器
    3. Vue根据传来的url提取数据
    4. Vue根据数据发送请求(ajax请求),将查询数据发送给后台
    5. 后台接受到数据后,查询数据,返回查询到的数据
    6. Vue接收到数据后,渲染到模板中
    7. 浏览器显示
  • 优缺点
    • 前端渲染
      • 速度快,减轻服务器压力,交互较好(loading等),不借助某些技术无法进行seo优化
    • 后端渲染
      • 便于seo优化,访问到的内容都在页面中

动态路由

  • 动态路由获取
    • 模板中
      • $route.params.x
    • js
      • this.$route.params.x
    • watch
      • to.params.x
  • 重定向
    • a跳转到b
      • 给a设置redirect--》b的路由
  • 别名
    • 当访问/a时,实际访问到的内容为b时,url显示为/a
      • 应该给/b加alias"/a"
  • 命名视图
    • 同级展示多个视图,而不是嵌套展示,可以使用命名视图
    • 一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件

路由组件传参

  • 在组件中使用$route会使之与对应路由形成高度耦合,从而使组件只能在某些特定的url上使用,限制了灵活性,可使用props将组件和路由解耦
  • { path: '/user/:id', component: User, props: true }routes中设置props为true时,默认传递$route.params
    • 组件配置对象中,可直接添加props属性,为其添加所需prop即可(如:id、tab等)
  • 你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
    • { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
    • 该返回对象将作为属性,传递给对应组件

HTML5 History模式

  • 使用history模式,可以使得URL像正常url(去掉#号)

导航守卫--》路由导航守卫--》路由钩子函数

  • 所有的路由都会经过全局导航守卫,所以在网页需要登录等操作才能访问时使用**
  • this.$route.query.xxx---->js函数中通过,获取url中查询字符串信息,此处为跳转至该页面的源页面
  • 通过this.$router.push(url)---->实现跳转至来时页面---》即登录过后跳转至页面
  • router.beforeEach((to,from,next)=>{}),(from来源,to去向,next守卫),to.fullPath(其中存放着url路径及查询字符串)
  • meta属性routes中添加对应属性,to.matched其中存放着当前网页的路径,以及其祖先url信息,可在其中找到对应的meta,运用数组some方法(存在该meta,即需要验证的页面)

全局解析守卫

  • beforeEach**
  • 类似router.beforeEach
  • 区别,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

全局后置钩子

  • afterEach((to,from)=>{})
  • 只有to,from**,不接受next函数,也不会改变导航本身

路由独享守卫

  • beforeEnter**
  • 在路由配置(routes)上直接定义
  • 与全局前置守卫的方法参数一样

组件内守卫

  • beforeRouteEnter
    • 在渲染该组件的对应路由被confirm前调用
    • !不能 !获取组件实例this----可以通过beforeRouteEnter(to, from, next) { console.log(this, 'beforeRouteEnter'); // undefined console.log(to, '组件独享守卫beforeRouteEnter第一个参数'); console.log(from, '组件独享守卫beforeRouteEnter第二个参数'); console.log(next, '组件独享守卫beforeRouteEnter第三个参数'); next(vm => { //因为当钩子执行前,组件实例还没被创建 // vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。 console.log(vm);//当前组件的实例 }); }---vm---vue官方使用--vue的实例---间接使用this
  • beforeRouteUpdate--2.2新增
    • 在当前路由改变,但是该组件被复用时调用--即虽然路由改变,但访问的仍然是同一个页面
    • 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    • // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    • 可以访问组件实例 this
  • beforeRouteLeave
    • 导航离开该组件的对应路由时调用
    • 可以访问组件实例this

完整的导航解析流程--官方(并非所有步骤都会执行)

  1. 导航被触发
  2. 在失活的组件里调用离开守卫
  3. 调用全局的beforeEach守卫
  4. 在重用的组件里调用veforeRouteUpdate
  5. 在路由配置里调用beforeEnter
  6. 解析异步路由组件
  7. 在被激活的组件里调用beforeRouteEnter
  8. 调用全局的beforeResolve守卫
  9. 导航被确认
  10. 调用全局的afterEach钩子
  11. 触发DOM更新
  12. 用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数

守卫与生命周期钩子函数的执行顺序

  • 全局 3
    • beforeEach
    • beforeResolve
    • afterEach
  • 路由独享 1
    • beforeEnter
  • 组件内 3
    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave
  • 导航守卫和声明周期钩子函数的执行先后顺序
    • 访问路由时
      • 全局守卫beforeEach先执行
      • 路由独享守卫beforeEnter执行
      • 组件内守卫beforeRouteEnter执行
      • 全局解析守卫beforeResolve执行
      • 最后全局后置守卫afterEach执行
      • 声明周期钩子函数执行
  • 切换路由时,如果路由是动态路由

    • 全局守卫beforeEach调用
    • 组件内守卫beforeRouteUpdate调用
    • beforeResolve调用
    • afterEach
    • // 如果数据也发生了变化,在路由结束后触发
    • beforeUpdate
    • updated
  • 切换路由时,路由不同

    • from befreRouteLeave
    • beforeEach
    • to 路由独享守卫beforeEnter
    • to 组件内守卫 beforeRouteEnter
    • 全局解析守卫beforeResolve
    • 全局后置守卫 afterEach
    • to 组件生命周期钩子,知道to组件创建完成
    • 销毁from的组件
    • to 组件挂载
  • 当组件切换时,先创建新组件,当新组件beforeMount(生命周期钩子函数-挂载前)之后,才销毁旧组件,旧组件销毁后,新组件被挂载

  • 生命周期钩子函数永远在路由afterEach之后执行

过渡动效

  • 过渡动效
    • 为router-view标签,添加transition标签
  • 单个路由的过渡
    • 给路由组件设置过渡效果,路由组件内使用transition,并设置不同的name属性
  • 基于路由的动态过渡
    • 基于当前路由与目标路由的变化关系,动态设置过渡效果
    • 基于路由变化使用对应的name值,实现路由不同,过渡效果的不同
  • Vue在插入、更新或则移除DOM时**,提供多种不同方式的过渡效果
    • 在css过渡和动画中自动应用class
    • 配合使用第三方css动画库,如Animate.css
    • 在过渡钩子函数中使用JavaScript直接操作DOM
    • 配合使用第三方JavaScript动画库,如Velocity.js
  • 单元素/组件的过渡
    • 条件渲染(使用v-if
    • 条件展示(使用v-show
    • 动态组件
    • 组件根节点

  • 当插入或删除包含在transition组件中的元素时
    1. 自动嗅探目标元素是否应用了css过渡或动画,如果是,在恰当的时机添加/删除css类名
    2. 如果过渡组件提供了JavaScript钩子函数,这些钩子函数将在恰当的时机被调用
    3. 如果没有找到JavaScript钩子并且也没有检测到css过渡/动画,DOM操作(插入/删除)在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和Vue的nextTick概念不同
  • 类名-六个class
    1. v-enter:定义过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除
    2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除,这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数
    3. v-enter-to:2.1.8版及以上定义进入过渡的结束状态,在元素被插入之后下一帧生效(于此同时v-enter被移除),在过渡/动画完成之后移除
    4. v-leave:定义离开过渡的开始状态,在离开过渡被触发时立刻生效,下一帧被移除
    5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数
    6. v-leave-to:2.1.8版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(与此同时v-leave被删除),在过渡/动画完成之后移除
    • 对于这些过渡中切换的类名来说,如果使用一个没有名字的<transition>,则v-是这些类名的默认前缀。如果使用了<transition name="my-transition">,那么v-enter会替换为my-transition-enter,即替换为transition标签中的name属性的值
  • 自定义过渡的类名
    • enter-class === v-enter
    • enter-active-class === v-enter-active
    • enter-to-class === v-enter-to
    • leave-class === v-leave
    • leave-active-class === v-leave-active
    • leave-to-class === v-leave-to
    • 添加到transition标签中,修改对应类名
    • 他们的优先级高于普通的类名,这对于Vue的过渡系统和其他第三方css动画库,如Animate.css结合使用十分有效
    • 不再需要为transition标签添加name属性
  • 同时使用过渡和动画
    • Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionend 或 animationend ,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。

    • 但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type 特性并设置 animation 或 transition 来明确声明你需要 Vue 监听的类型

Vueg插件

  • 为webApp提供转场特效的开源Vue插件
  • Vueg

Vuex-状态管理模式

  • 借鉴The Elm ArchitectureReduxFlux,与其他模式不同的是,Vuex是专门为Vue.js设计的状态管理库,以利用Vue.js的细粒度数据响应机制来进行高效的状态更新

  • 什么情况下使用Vuex

    • 如果不开发大型单页应用,使用Vuex可能是繁琐冗余的
    • 如果应用够简单,最好不要使用Vuex,简单的store模式足够了
  • Vuex与单纯的全局对象的区别

    1. Vuex的状态存储是响应式的,当Vuex组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的得到高效更新
    2. 不能直接改变store中的状态,改变store中的状态的唯一途径就是显示的提交(commit)mutation,这样使得我们方便的追踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好的了解我们的应用
  • State

    • 可以在需要使用store中数据的组件的computed中新建对应state中数据的方法,将state中的数据返回即可直接使用computed:{msg(){return this.$store.state.xxx}}
    • mapState-辅助函数
      • 当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余,使用mapState辅助函数帮助我们生成计算属性
      • computed:mapState({count:state=>state.count,countAlias:"count"})-->使用箭头函数可使代码更简练,但有时为能使用this获取局部状态,必须使用常规函数--但是这种写发造成非store相关数据无法写入
      • 对象展开运算符
        • 使用对象展开运算符将此对象混入到外部对象中computed:{localComputed(){},...mapState({})}
  • Getter

    • 从store的state中派生出一些状态
    • getter接收state作为第一个参数,也可以接收其他getter作为第二个参数
    • 通过让getter返回一个函数,实现getter传参,getter在通过方法访问时,每次都会进行调用,而不会缓存结果
  • Mutation--提交

    • 更改Vuex的store中的状态的位移方法是提交mutation。Vuex中的mutation非常类似于事件,每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且会接受state作为第一个参数
      • 触发。this.$store.commit('xx')
      • 提交载荷(payload)。mutations:{xxx(state,n){}}--state作为第一个参数,第二个参数为载荷,大多数情况下载荷应该是一个对象
      • 对象风格的提交。this.$store.commit({type:'xxx',cs:xx})--type即为mutations中的事件名,其他均为参数
    • Mutation需遵守Vue的响应规则
      1. 最好提前在store中初始化所有所需属性
      2. 当需要在对象上添加新属性时,应该:
        • 使用Vue.set(obj,'newProp',123),或者
        • 以新对象替换老对象。state.obj={...state.obj,newProp:123}
    • 使用常量替代Mutation事件类型
      • 使用常量替代mutation事件类型在各种Flux实现中是很常见的模式。这样可以使linter之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个app包含的mutation一目了然 ,--即将mutation中的事件名作为一个对象的属性存入对象中[obj.name]作为mutation中的事件名,可以更直观的了解各事件的功能
    • Mutation必须是同步函数
    • 在Vuex中,mutation都是同步事物
  • Action--分发

    • Action类似于mutation,不同之处在于:
      1. Action提交的是mutation,而不是直接变更状态
      2. Action可以包含任意一步操作
    • actions:{xxx(context){context.commit('xxx')}}--actions中处理的都是异步操作,改变数据时最后一步都是调用mtation即context.commit()
    • 使用参数解构/解构赋值来简化代码(特别是需要调用commit很多次的时候)--actions:{xxx({commit}){commit('xxx')}}--通过结构复制直接得到context中的commit调用mutation中对应的事件处理
    • 触发
      • this.$store.dispath('xxx')
    • 因为mutation中只能执行同步操作,所以只能通过actions内部执行异步操作后调用mutation--actions:{xx({commit}){setTimeout(()=>{commit('xxx')},1000)}}--一秒后调用commit('xx')执行mutation中的对应处理事件
    • Actions支持同样的载荷方式和对象方式进行分发
  • module

    • 模块中有自己的state,将其放入store的modules中后,其state会变成rootState(最外层store中的state)
      • this.$store.state.模块名 //这就是对应模块中的state对象
    • getters最终会变成root中的getters
      • module={getters:{getter名字(state,getters,rootState,rootGetter){}}}--state是当前模块的状态,rootState是根store的state
      • 如果没有namespaced:true属性那么getter就是rootstore的getter,如果有该属性getters就是模块中的getter,第四个参数rootGetter才是全局中全部的getter
      • this.$store.getters.getter名字
      • 如果给模块添加namespaced:true那么对应的getter,mutation,action都会变成“对应模块名/对应名字”--区分rootstore与模块中的getter,mutation,action
      • 如果模块中有namespaced属性,那么commit('mutation')只能触发模块内的mutation
        • 如果在commit第三个参数中添加{root:true}-则触发的是全局的mutation--commit('mutation名字',payload,{root:true})--dispatch同理
      • 模块创建
        • new Vuex.Store({modules:{模块名:{}}})
        • 分开--const module={} new Vuex.Store({modules:{模块名:module}})
        • 模块中也有state,getters,mutations,actions,modules
        • 单个模块当做一个store即可
          • state
            • this.$store.state
              • 模块中的state
                • this.$store.state.模块名
          • getters,actions,mutations--直接会添加到rootstore中的对应位置
          • 如果给模块添加namespaced:true
            • name对应的getters,mutations,actions会变成 模块名/名字 的形式,并且可以与rootstore中的姓名重合,因为名字之前带有各自模块名
              • 同时,直接在模块中commit('mutation')/dispatch('action'),默认提交/分发的是模块中的mutation/action
              • 想要调用全局,需要在之后加上{root:true}
                • commit('mutation',payload,{root:true})
                • dispatch('action',payload,{root:true})
          • 辅助函数如果想要使用命名空间模块中的内容
            • mapState({msg:state=>state.模块名.msg})
            • mapState('模块名',['msg'])
  • 代码

  var store = new Vuex.Store({
    state:{

    },
    mutations:{

    },
    getters:{

    },
    actions:{

    }
  })
  this.$store.state.xx  //获取state中存储的数据
  • input v-model处理方法**
    • 详见Vuex-表单处理
    • 当页面中存在input等表单元素时,需要使用v-model,但store中state无法与computed直接修改
    • 所以将computed的书写格式写成computed:{msg:{get(){//获得state中的数据},set(value){//value 当页面中form表单中的数据发生变化时触发,值即为修改后的数据 可在此提交mutation修改state中的对应数据 this.$store.commit('setMsg',value)}}}
    • computed对象中的get方法用来获取store里state中的数据,显示到页面,而set方法中的value则为页面中表单数据发生变化后的值,可在触发后将值作为载荷提交mutation修改state中的数据
  • axios拦截器**
    • 在请求或响应thencatch处理前拦截它们
    • 对发送前数据添加token,或设置请求头,验证等
    • 对响应数据做处理,剥离外层结构等
    //添加请求拦截器
    axios.interceptors.request.use(function(config){
      //在发送请求之前做些什么
      return config;
    },function(error){
      //对请求错误做些什么
      return Promise.reject(error);
    });
          // axios.interceptors.request.use(config=>config,error=>Promise.reject(error))
    //添加响应拦截器
    axios.interceptors.response.use(function(response){
      //对响应数据做点什么
      return response;
    },function(error){
      //对响应错误做点什么
      return Promise.reject(error);
    })
          /*
            axios.interceptors.response.use(response=>response,error=>Promise.reject(error))
          */

keep-alive

  • 切换组件外层添加<keep-alive></keep-alive>可以缓存组件的状态,当再次切换后显示之前的状态--默认情况下组件被v-if隐藏后经历destroy周期,再次显示时触发create,mount周期,不会保留之前的访问状态
  • 属性
    • include 符合条件的组件会被缓存
      • 字符串
        • 逗号隔开组件
      • 正则
        • 符合比正则表达式的会被缓存--v-bind:include
      • 数组
        • ['组件名','组件名']
        • v-bind:include
    • exclude与include相仿,符合条件的不会被缓存
  • Props:
    • include-字符串或正则表达式,只有匹配的组件会被缓存
    • exclude-字符串或正则表达式,任何匹配的组件都不会被缓存
  • 用法
    • <keep-alive>包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和<transition>相似,<keep-alive>是一个抽象的组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中。当组件在<keep-alive>内被切换,它的activateddeactivated这两个声明周期钩子函数将会被对应的执行
    • 主要用于保留组件状态或避免重新渲染
    • include、exclude--匹配检查先检查组件自身的name选项,如果name选项不可用,则匹配他的局部注册名称(父组件components选项的键值)。匿名组件不能被匹配
    • activated--keep-alive组件激活时调用
    • deactivated--keep-alive组件停用时调用
    • 由于keep-alive的组件缓存,切换组件时不会触发对应的destroy,create,mount周期函数

ref

  • ref可以添加在组件或者html标签上
  • 可以通过this.$refs.自定义名字获取
  • created生命周期中无法获取DOM,因为created时页面还没有渲染
  • ref加在html标签上,得到对应的DOM对象
  • ref加载组件标签上,得到的是对应组件的组件对象

nextTick

  • this.$nextTick(()=>{//这里的代码会在每次更新后,页面DOM更新后才会触发})

对象操作

  • 如果对象某个值不存在,先要添加新的值,并试数据响应--不能使用app.对象.新属性=值
  • 需要使用Vue.set方法
    • Vue.set(对象,'属性','值')
    • app.$set(对象,'属性','值')
    • Vue.delete(对象,'属性')
    • Vue.$delete(对象,'属性')

自定义指令

  • 想要对DOM元素进行原生操作时,可以使用自定义指令
  • Vue.directive('指令名(不加v-)',{})
  • 自定义指令共5个钩子函数
    • bind
    • inserted
    • update
    • componentUpdated
    • unbind
  • 参数
    • el 指令绑定的元素的DOM对象可以直接操作DOM
    • binding
      • name 指令名
      • value 指令后等于的值 v-指令名='value'
      • oldValue 仅在update和componentUpdated中存在
      • expression 指令表达
      • arg 参数 v-on:click click就是参数
      • modifiers v-on:click.stop stop就是修饰符
        • 修饰符可以有多个,所以修饰符是一个对象
      • vnode Vue 产生的虚拟节点
      • oldVnode 上一个虚拟节点

slot插槽

  • 正常情况下template中,标签中的内容会被忽略,而slot标签相当于,预留的插槽,可以实现内容的正常显示
  • 在两slot标签中的内容会被当做默认值,即当后期不插入内容时,显示默认值
  • 优点:方便后期组件使用,和更改对应信息

具名插槽-name属性

  • slot标签有多个时,为避免混乱,可以为其添加name属性
  • 当使用时,可以在标签中添加slot属性,其值为对应slot名-(造成多余标签)
  • 可以通过<template slot="slotname"></template>来实现,该标签不会显示在页面中

默认内容

  • 当在slot标签之间填写内容时,会被当做默认内容,当不在组件标签之间填写内容时,显示默认内容,填写则覆盖默认值
  • 具名标签slot标签之间添加默认内容无效
  • 具名插槽会与具有slot属性的标签一一对应,多余的内容会在不具名slot中统一显示,如果不存在该标签,则内容舍弃

作用域插槽(flot-scope="自定义名字")

  • 改变从子组件获取的数据结构???

  • 创建组件时

    • 在slot标签上添加的属性
    • <slot 数据名="值" 数据名2="值2"></slot>
    • 使用组件时,会出现在组件标签内部的slot-scope上
      <组件标签>
      • div slot-scope="自定义名字"">
      • // 自定义名字就是一个对象,对象上包含了所有的slot标签上的属性
      • /div>
      • </组件标签>
  • 作用域插槽的意义

    • 将数据给对应的组件,让使用组件的人可以自定义组件的模板

@click==v-on:click

  • 写在template中的v-on:click(click事件)可以正常触发
  • 但是,当写在组件标签中时,会被当做是监听(自定义事件名)**
  • 所以**,如果想要在组件标签中写@click事件,可以使用修饰符.native--》声明该click为原生click事件
  • 或者在template中,为@click添加自定义事件,即子到父通信,可传递数据,否则无法触发click事件**

Element UI-》组件库

vue-cli

  • 命令行工具
    • Vue 提供了一个官方的 CLI,为单页面应用快速搭建 (SPA) 繁杂的脚手架。它为现代前端工作流提供了 batteries-included 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint 校验,以及生产环境可用的构建版本。更多详情可查阅 Vue CLI 的文档
    • 安装步骤
      • cnpm install -g vue-cli--(全局安装vue-cli)
      • vue init list name path--(初始化 vue init list(模板类型-通过vue-list查看) name(项目名) path(不写,默认为当前路径))
      • vue init webpack + 项目名称(不能包含大写)
    • 创建
      • ? Project name 输入项目名称

      • ? Project description 输入项目描述

      • ? Author 作者

      • ? Vue build 打包方式,回车就好了

      • ? Install vue-router? 选择 Y 使用 vue-router,输入 N 不使用

      • ? Use ESLint to lint your code? 代码规范,推荐 N

      • ? Setup unit tests with Karma + Mocha? 单元测试,推荐 N

      • ? Setup e2e tests with Nightwatch? E2E测试,N

    • 运行
      • 进入对应文件,路径
      • cnpm install--(安装所需组件)
      • npm start/npm run dev
    • 编写
      • sc--快捷生成template script style结构
    • 插件
      • Vetur


作者:wudongyu
链接:https://www.jianshu.com/p/eb4c36319cd4
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2019-11-11 13:50  青石小巷  阅读(310)  评论(0编辑  收藏  举报