Vue高版本中一些新特性的使用详解


Posted in Javascript onSeptember 25, 2018

一、深度作用选择器( >>> )

严格来说,这个应该是vue-loader的功能。”vue-loader”: “^12.2.0”

在项目开发中,如果业务比较复杂,特别像中台或B端功能页面都不可避免的会用到第三方组件库,产品有时会想对这些组件进行一些UI方面的定制。如果这些组件采用的是有作用域的CSS,父组件想要定制第三方组件的样式就比较麻烦了。

深度作用选择器( >>> 操作符)可以助你一臂之力。

<template>
<div>
  <h1 class="child-title">
    如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作
  </h1>
</div>
</template>

<script>
export default {
  name: 'child',
  data() {
    return {
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.child-title {
  font-size: 12px;
}
</style>

上面的child组件中 .child-title 的作用域CSS设定字体大小为12px,现在想在父组件中定制为大小20px,颜色为红色。

<template>
<div>
  <child class="parent-custom"></child>
</div>
</template>
<script>
import Child from './child';
export default {
  name: 'parent',
  components:{
    Child
  },
  data() {
    return {
    }
  }
}
</script>

<style>
.parent-custom >>> .child-title {
  font-size:20px;
  color: red;
}
</style>

效果妥妥的。但是别高兴太早,注意到上面的style使用的是纯css语法,如果采用less语法,你可能会收到一条webpack的报错信息。

<style lang="less">
.parent-custom {
   >>> .child-title {
    font-size:20px;
    color: red;
  }
}
</style>
ERROR in ./~/css-loader!./~/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-960c5412","scoped":false,"hasInlineConfig":false}!./~/postcss-loader!./~/less-loader!./~/vue-loader/lib/selector.js?type=styles&index=0!./src/components/parent.vue
Module build failed: Unrecognised input
 @ /src/components/parent.vue (line 22, column 6)
 near lines:
  .parent-custom {
    >>> .child-title {
      font-size:20px;

上面的报错信息其实是less语法不认识 >>>。(less的github issue上有人提议支持>>>操作符,但本文使用的v2.7.3会有这个问题)

解决方案是采用的less的转义(scaping)和变量插值(Variable Interpolation)

<style lang="less">
@deep: ~'>>>';
.parent-custom {
   @{deep} .child-title {
    font-size:20px;
    color: red;
  }
}
</style>

对于其他的css预处理器,因为没怎么用,不妄加评论,照搬一下文档的话。

有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 操作符取而代之——这是一个 >>> 的别名,同样可以正常工作。

二、组件配置项inheritAttrs、组件实例属性$attrs和$listeners

2.4.0新增

组件配置项 inheritAttrs

我们都知道假如使用子组件时传了a,b,c三个prop,而子组件的props选项只声明了a和b,那么渲染后c将作为html自定义属性显示在子组件的根元素上。

如果不希望这样,可以设置子组件的配置项 inheritAttrs:false,根元素就会干净多了。

<script>
export default {
  name: 'child',
  props:['a','b'],
  inheritAttrs:false
}
</script>

组件实例属性$attrs和$listeners

先看看vm.$attrs文档上是怎么说的

vm.$attrs

类型:{ [key: string]: string }

只读

包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建高级别的组件时非常有用。

归纳起来就是两点:

vm.$attrs是组件的内置属性,值是父组件传入的所有prop中未被组件声明的prop(class和style除外)。

还是以前面的child组件举例

//parent.vue
<template>
  <div>
    <child class="parent-custom" a="a" b="b" c="c"></child>
  </div>
</template>

//child.vue
<script>
export default {
  name: 'child',
  props:['a','b'],
  inheritAttrs:false,
  mounted(){
    //控制台输出:
    //child:$attrs: {c: "c"}
    console.log('child:$attrs:',this.$attrs);
  }
}
</script>

组件可以通过在自己的子组件上使用v-bind=”$attrs”,进一步把值传给自己的子组件。也就是说子组件会把$attrs的值当作传入的prop处理,同时还要遵守第一点的规则。

//parent.vue
<template>
  <div>
    <child a="a" b="b" c="c"></child>
  </div>
</template>
//child.vue
<template>
  <div>
    <grand-child v-bind="$attrs" d="d"></grand-child>
  </div>
</template>
<script>
export default {
  name: 'child',
  props:['a','b'],
  inheritAttrs:false
}
</script>
//grandchild.vue
<script>
export default {
  name: 'grandchild',
  props:[],
  //props:['c'],
  inheritAttrs:false,
  mounted(){
    //控制台输出:
    //grandchild:$attrs: {d: "d", c: "c"}
    console.log('grandchild:$attrs:',this.$attrs);
    //如果props:['c']
    //控制台输出:
    //grandchild:$attrs: {d: "d"}
  },
}
</script>

vm.$listeners

类型:{ [key: string]: Function | Array }

只读

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件——在创建更高层次的组件时非常有用。

归纳起来也是两点:

1、vm.$listeners是组件的内置属性,它的值是父组件(不含 .native 修饰器的) v-on 事件监听器。
2、组件可以通过在自己的子组件上使用v-on=”$listeners”,进一步把值传给自己的子组件。如果子组件已经绑定$listener中同名的监听器,则两个监听器函数会以冒泡的方式先后执行。

//parent.vue
<template>
  <div>
    <child @update="onParentUpdate"></child>
  </div>
</template>
<script>
export default {
  name: 'parent',
  components:{
    Child
  },
  methods:{
    onParentUpdate(){
      console.log('parent.vue:onParentUpdate')
    }
  }
}
</script>
//child.vue
<template>
  <div>
    <grand-child @update="onChildUpdate" v-on="$listeners"></grand-child>
  </div>
</template>
<script>
export default {
  name: 'child',
  components:{
    GrandChild
  },
  methods:{
    onChildUpdate(){
      console.log('child.vue:onChildUpdate')
    }
  }
}
</script>
//grandchild.vue
<script>
export default {
  name: 'grandchild',
  mounted(){
    //控制台输出:
    //grandchild:$listeners: {update: ƒ}
    console.log('grandchild:$listeners:',this.$listeners);
    //控制台输出:
    //child.vue:onChildUpdate
    //parent.vue:onParentUpdate
    this.$listeners.update();
  }
}
</script>

三、组件选项 provide/inject

2.2.0 新增

如果列举Vue组件之间的通信方法,一般都会说通过prop,自定义事件,事件总线,还有Vuex。provide/inject提供了另一种方法。

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

如果你熟悉 React,这与 React 的上下文特性(context)很相似。

不过需要注意的是,在文档中并不建议直接用于应用程序中。

provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

//parent.vue
<template>
  <div>
    <child></child>
  </div>
</template>
<script>
export default {
  name: 'parent',
  provide: {
    data: 'I am parent.vue'
  },
  components:{
    Child
  }
}
</script>
//child.vue
<template>
  <div>
    <grand-child></grand-child>
  </div>
</template>
<script>
export default {
  name: 'child',
  components:{
    GrandChild
  }
}
</script>
//grandchild.vue
<script>
export default {
  name: 'grandchild',
  inject: ['data'],
  mounted(){
    //控制台输出:
    //grandchild:inject: I am parent.vue
    console.log('grandchild:inject:',this.data);
  }
}
</script>

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。
inject 选项应该是一个字符串数组或一个对象,该对象的 key 代表了本地绑定的名称,value 就为provide中要取值的key。

在2.5.0+时对于inject选项为对象时,还可以指定from来表示源属性,default指定默认值(如果是非原始值要使用一个工厂方法)。

const Child = {
 inject: {
  foo: {
   from: 'bar',
   default: 'foo'
   //default: () => [1, 2, 3]
  }
 }
}

四、作用域插槽 slot-scope

2.1.0 新增

在 2.5.0+,slot-scope 不再限制在 template 元素上使用,而可以用在插槽内的任何元素或组件上。

作用域插槽的文档说明很详细。下面举个例子来展示下应用场景。

Vue高版本中一些新特性的使用详解

可以看出列表页和编辑页对于数据的展示是一样的,唯一的区别是在不同页面对于数据有不同的处理逻辑。相同的数据展示这块就可抽取成一个组件,不同的地方则可以借助作用域插槽实现。

//data-show.vue
<template>
<div>
  <ul>
    <li v-for="item in list">
      <span>{{item.title}}</span>
      <slot v-bind:item="item">
      </slot>
    </li>
  </ul>
</div>
</template>

//list.vue
<template>
<p>列表页</p>
  <data-show :list="list">
    <template slot-scope="slotProps">
      <span v-if="slotProps.item.complete">✓</span>
      <span v-else>x</span>
    </template>
  </data-show>
</template>

//edit.vue
<template>
<p>编辑页</p>
  <data-show :list="list">
    <template slot-scope="slotProps">
      <a v-if="slotProps.item.complete">查看</a>
      <a v-else>修改</a>
    </template>
  </data-show>
</template>

五、Vue的错误捕获

全局配置errorHandler

从2.2.0起,这个钩子也会捕获组件生命周期钩子里的错误。
从 2.4.0 起这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了。

更详细的说明可以查看文档errorHandler

生命周期钩子errorCaptured

2.5.0+新增

更详细的说明可以查看文档errorCaptured

如果熟悉React的话,会发现它跟错误边界(Error Boundaries)的概念很像,实际上也确实是这么用的。

在文档Error Handling with errorCaptured Hook就举了一个典型的例子

Vue.component('ErrorBoundary', {
 data: () => ({ error: null }),
 errorCaptured (err, vm, info) {
  this.error = `${err.stack}\n\nfound in ${info} of component`
  return false
 },
 render (h) {
  if (this.error) {
   return h('pre', { style: { color: 'red' }}, this.error)
  }
  // ignoring edge cases for the sake of demonstration
  return this.$slots.default[0]
 }
})
<error-boundary>
 <another-component/>
</error-boundary>

需要强调的是errorCaptured并不能捕获自身错误和异步错误(比如网络请求,鼠标事件等产生的错误)。

In 2.5 we introduce the new errorCaptured hook. A component with this hook captures all errors (excluding those fired in async callbacks) from its child component tree (excluding itself).

参考

https://github.com/vuejs/vue/releases

https://github.com/vuejs/vue-loader/releases

总结

以上所述是小编给大家介绍的符Vue高版本中一些新特性的使用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JQuery select标签操作代码段
May 16 Javascript
谈一谈JS消息机制和事件机制的理解
Apr 14 Javascript
AngularJS中的指令全面解析(必看)
May 20 Javascript
微信小程序 页面跳转传参详解
Oct 28 Javascript
div中文字内容溢出常见的解决方法
Mar 16 Javascript
原生JS实现不断变化的标签
May 22 Javascript
Angular指令之restict匹配模式的详解
Jul 27 Javascript
vue项目中的webpack-dev-sever配置方法
Dec 14 Javascript
基于VuePress 轻量级静态网站生成器的实现方法
Apr 17 Javascript
获取layer.open弹出层的返回值方法
Aug 20 Javascript
JavaScript 空间坐标的使用
Aug 19 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
Sep 04 Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
Sep 25 #Javascript
vue实现多个元素或多个组件之间动画效果
Sep 25 #Javascript
vue 音乐App QQ音乐搜索列表最新接口跨域设置方法
Sep 25 #Javascript
Vue页面跳转动画效果的实现方法
Sep 23 #Javascript
vue解决弹出蒙层滑动穿透问题的方法
Sep 22 #Javascript
vue如何解决循环引用组件报错的问题
Sep 22 #Javascript
开发一个Parcel-vue脚手架工具(详细步骤)
Sep 22 #Javascript
You might like
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
php 前一天或后一天的日期
2008/06/28 PHP
php过滤危险html代码
2008/08/18 PHP
PHPExcel中文帮助手册|PHPExcel使用方法(分享)
2017/06/09 PHP
PHP中PDO事务处理操作示例
2018/05/02 PHP
Ubuntu中支持PHP5与PHP7双版本的简单实现
2018/08/19 PHP
11款新鲜的jQuery插件[附所有demo下载]
2011/01/24 Javascript
分享一个asp.net pager分页控件
2012/01/04 Javascript
jQuery事件绑定.on()简要概述及应用
2013/02/07 Javascript
网页广告中JS代码的信息监听示例
2014/04/02 Javascript
45个JavaScript编程注意事项、技巧大全
2015/02/11 Javascript
jQuery动态修改超链接地址的方法
2015/02/13 Javascript
javascript实现全局匹配并替换的方法
2015/04/27 Javascript
jquery插件jquery.confirm弹出确认消息
2015/12/22 Javascript
基于jquery实现智能表单验证操作
2016/05/09 Javascript
如何实现星星评价(jquery.raty.js插件)
2016/12/21 Javascript
详解vue-router 2.0 常用基础知识点之router.push()
2017/05/10 Javascript
vue.js $refs和$emit 父子组件交互的方法
2017/12/20 Javascript
详解如何实现一个简单的 vuex
2018/02/10 Javascript
Python中endswith()函数的基本使用
2015/04/07 Python
PYTHON 中使用 GLOBAL引发的一系列问题
2016/10/12 Python
python机器学习理论与实战(六)支持向量机
2018/01/19 Python
python 与服务器的共享文件夹交互方法
2018/12/27 Python
Python 根据日志级别打印不同颜色的日志的方法示例
2019/08/08 Python
python 进程间数据共享multiProcess.Manger实现解析
2019/09/23 Python
前端制作动画的几种方式(css3,js)
2016/12/12 HTML / CSS
CSS3制作hover下划线动画
2017/03/27 HTML / CSS
查找廉价航班和发现新目的地:Kiwi.com
2019/02/25 全球购物
C#如何进行LDAP用户校验
2012/11/21 面试题
如何拷贝一整个Java对象,包括它的状态
2013/12/27 面试题
建筑系毕业生自我鉴定
2014/01/24 职场文书
中青班党性分析材料
2014/02/16 职场文书
电焊工岗位工作职责
2014/07/09 职场文书
爱牙日宣传活动总结
2015/02/05 职场文书
欠款纠纷起诉状
2015/05/19 职场文书
中国古代史学名著《战国策》概述
2019/08/09 职场文书