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 )

相關文章
相關標籤/搜索