Vue中少见但实用的技巧

     摘自:https://div.io/topic/1880,并加入一点本身实际练习的demo,记录下学习历程,并方便后续翻阅。html


1、vue动态组件:is

     关于is的妙用,参考另外一篇本身写的demo文章:https://juejin.im/editor/drafts/5c863924e51d4561a0778dd5vue

2、递归组件

     对于一些有规律的 dom 结构,咱们能够经过递归方式来生成这个结构,在 vue 的模板中递归生成dom。
git

     官方介绍:https://cn.vuejs.org/v2/guide/components-edge-cases.html#%E5%BE%AA%E7%8E%AF%E5%BC%95%E7%94%A8github

demo详见:https://github.com/elainema/elaine/tree/master/VUE/vue-components/src/views/component-communication和https://github.com/elainema/elaine/tree/master/VUE/vue-components/src/views/recursive-componentsvuex

 准备数据

     首先为了使用递归组件须要准备一份数据,由于此次是生成一个菜单,因此准备一个菜单书数据,新建一个testdata.js 文件代码以下:api

var demoData = [    {      'id': '1',      'menuName': '基础管理',      'menuCode': '10',      'children': [        {          'menuName': '用户管理',          'menuCode': '11'        },        {          'menuName': '角色管理',          'menuCode': '12',          'children': [            {              'menuName': '管理员',              'menuCode': '121'            },            {              'menuName': 'CEO',              'menuCode': '122'            }          ]        },        {          'menuName': '权限管理',          'menuCode': '13'        }      ]    },    {      'id': '2',      'menuName': '商品管理',      'menuCode': ''    }  ];    export default  demoData;复制代码

创建树形组件

如今创建树形组件,首先新建一个文件treeMenu,代码以下浏览器

<template><div>  <li>    <span @click="toggle">      <i v-if="hasChild" class="icon" v-bind:class="[open ? 'folder-open': 'folder' ]"></i>      <i v-if="!hasChild" class="icon file-text"></i>      {{model.menuName}}    </span>    <ul v-show="open" v-if="hasChild">      <tree-menu v-for="(item,index) in model.children"  v-bind:model="item" v-bind:key="index"></tree-menu>    </ul>  </li></div></template><script>  export default {    name: "TreeMenu",    inheritAttrs:false,    props: ['model'],    data(){      return {        open:false      }    },    computed:{      hasChild(){        return this.model.children && this.model.children.length      }    },    methods:{      toggle(){        if(this.hasChild){          this.open = !this.open        }      }    }  }</script><style>  ul {    list-style: none;    margin: 10px 0;  }  li {    padding: 3px 0;  }  li > span {    cursor: pointer;    font-size: 14px;    line-height: 20px;  }  i.icon {    display: inline-block;    width: 20px;    height: 20px;    margin-right: 5px;    background-repeat: no-repeat;    vertical-align: middle;  }  .icon.folder {    background-image: url(/src/assets/folder.png);  }  .icon.folder-open {    background-image: url(/src/assets/folder-open.png);  }  .icon.file-text {    background-image: url(/src/assets/file-text.png);  }  .tree-menu li {    line-height: 1.5;  }</style>复制代码

上述代码中咱们须要注意,这个组件必须含有 name 这个属性,由于没有 name 这个属性会形成控件自身不能调用自身,自身调用的时候最好有绑定 key ,由于这个 key 是惟一的标识,对于 vue 更新控件比较好.除非控件很是简单就不用 key.bash

另一个须要注意就是递归组件时候,须要有一个条件来终止递归,在这里使用 v-for 隐形条件终止递归. 

3、自定义组件使用 v-model

咱们知道,v-model是在表单类元素上进行双向绑定时使用的,好比:
iview

<template>
    <input type="text" v-model="data">
    {{ data }}
</template>
<script>
    export default {
        data () {
            return {
                data: ''
            }
        }
    }
</script>复制代码
这时 data就是双向绑定的,输入的内容会实时显示在页面上。在 Vue 1.x 中,自定义组件可使用 props 的 .sync双向绑定,好比:

<my-component :data.sync="data"></my-component>复制代码

在 Vue 2.x 中,能够直接在自定义组件上使用 v-model了,好比:
dom

<my-component v-model="data"></my-component>复制代码

在组件my-component中,经过this.$emit('input')就能够改变data的值了。

4、Vue 父子组件数据传递( inheritAttrs + $attrs + $listeners)

当咱们在书写 vue 组件的时候,常常会用到数据传递;将父组件的数据传递给子组件,有时候也须要经过子组件去事件去触发父组件的事件;总结一下比较经常使用的三种解决办法:

  1. 经过 props 的方式向子组件传递(父子组件)

  2. vuex 进行状态管理(父子组件和非父子组件) 

  3. 父组件经过this.$refs[子组件ref]  可直接调用子组件的方法

    //  父组件
    <template>    <child ref="child"></child></template><script>export default {    name:'parent',    mounted() {        this.refs.child.childSubmit()    }}</script>
    // 子组件
    <template>    <div>        这是一个子组件    </div></template><script>export default {    name:'parent',    methods:{        childSubmit() {            alert("trigger")        }    }}</script>复制代码

后来在查看iview和element源码的时候发现还有第四种传递方式, inheritAttrs + $attrs + $listeners

基本是大部分的公司或者项目都是用前面两种,我也不例外......初次看到第四种写法时甚至有些惊讶,原来还有这种写法,而后去API看才发现其实很早就有,只是没有仔细看文档......故整理一下,若是有需求能够尝试用一用,官方api地址(英文看到很懵,转中文文档先看。。。):https://cn.vuejs.org/v2/api/index.html#inheritAttrs

一、场景介绍

vue中一个比较使人烦恼的事情是属性只能从父组件传递给子组件。这也就意味着当你想向嵌套层级比较深组件数据传递,只能由父组件传递给子组件,子组件再传递给孙子组件...像下面这样:

<parent-component :passdown="passdown">

<child-component :passdown="passdown">

<grand-child-component :passdown="passdown">

....

就这样一层一层的往下传递passdown这个变量,最后才会用{{passdown}}。复制代码

假如咱们须要传递的属性只有1,2个还行,可是若是咱们要传递的有几个或者10来个的状况,这会是什么样的场景,咱们会在每一个组件不停的props,每一个必须写不少遍。有没有其它方便的写法?有,经过vuex的父子组件通讯,的确这个是一个方法,可是还有其它的方法,这个就是咱们要说的。经过inheritAttrs选项,以及实例属性$attrs

inheritAttrs + $attrs + $listeners

说实话,官方的解释开始看了几遍也是云里雾里的,忽略个人理解力。。。

二、实例:

父组件ComponentCommunication.vue

<template>    <div class="">        <MyTest :title="title" :massgae="massgae"></MyTest>    </div></template><script>import MyTest from './MyTest.vue'export default {    name:'componentCommunication',    data () {        return {            title:'定义在父组件的title',            massgae:'message111'        }    },    components:{        MyTest    },    created:function(){    }}</script>复制代码

子组件MyTest.vue

<template><section>    <div>这里是标题,父组件经过prop传递给子组件的:{{title}}</div>    <div> 注意这里:this.$attrs{{$attrs}}</div></section></template><script>export default {    props:['title'],    data(){        return{        }    },    created:function(){        console.log(this.$attrs)//注意这里    }}</script>复制代码

上边的代码,父组件传递了两个参数给子组件title和message,在子组件里只注册并使用了title,massgae并无注册和使用,那么下浏览器渲染出来是什么样呢?以下图:



咱们看到:子组件内未被注册的属性将做为普通html元素属性被渲染,若是想让属性可以向下传递,即便prop组件没有被使用,你也须要在组件上注册。这样作会使组件预期功能变得模糊不清,同时也难以维护组件,尤为是多层嵌套传递的场景。

在Vue2.4.0,能够在组件定义中添加inheritAttrs:false,组件将不会把未被注册的props呈现为普通的HTML属性。

$attrs

关于Props 的一个使人讨厌的事情是,他们只能从父母传给孩子。 这意味着若是您有深刻的嵌套组件,您须要传递数据,则必须将数据做为Props 绑定到每一个中间组件中:

对于一个或两个 Props 来讲还好,可是在一个真正的项目中,你可能会有许多更多的东西要传下去。
您可使用事件总线或Vuex来解决此问题,但Vue 2.4.0提供了另外一种解决方案。 实际上,它是两个独立但相关的新功能的一部分:首先,一个称为 inheritAttrs的组件的标志,其次是一个实例属性 $attrs。 在组件里咱们能够经过其$attrs能够获取到父组件传递给子组件,但子组件没有使用和注册的数据。

inheritAttrs

咱们在子组件里设置 inheritAttrs: false  // 默认是true,  渲染效果以下,能够看到父组件传递给组件的参数,但子组件未注册和使用的,不会做为普通html元素被渲染


$listeners

个人理解就是:子组件能够触发父组件的事件(不须要用什么那些麻烦的vuex或者一个空的 Vue实例做为事件总线,或者又是什么vm.$on )

相关文章
相关标签/搜索