通俗易懂--快速入門Vue--3


1.組件使用的細節點1

  • is屬性在tbody中應用
<div id="root">
    <table>
        <tbody>
            <row></row>
            <row></row>
            <row></row>
        </tbody>
    </table>
</div>
<script>
    Vue.component('row',{
        template:`<tr><td>this is a row</td></tr>`
    });


    var vm = new Vue({
        // el限制一個vue實例的管理范圍。
        el:"#root",
    });

</script>
  • 看似上面代碼書寫沒有什么問題,但是打開頁面你會看到,如下圖:

    所有的tr標簽都跑到了tbody外面,這是不符合規范的。

  • 那么如何解決這個問題,通過is屬性,只需要在原來代碼改一下:

    <div id="root">
        <table>
            <tbody>
                <tr is="row"></tr>
                <tr is="row"></tr>
                <tr is="row"></tr>
            </tbody>
        </table>
    </div>
    

    原有的html實例不變,這樣就可以避免tr標簽上升到tbody標簽外頭了。

  • 同樣像ul(li),select(option)

    <ul>
    	<li is="row"></li>
    	<li is="row"></li>
    	<li is="row"></li>
    </ul>
    
    <select>
        <option is="row"></option>
        <option is="row"></option>
        <option is="row"></option>
    </select>
    

2.組件使用的細節點2

  • data在子組件中,必須為一個函數,同時函數有返回數據。

    Vue.component('row',{
            data:function(){
                return {
                    content:"this is content"
                }
            },
            template:`<tr><td>{{content}}</td></tr>`
        });
    

3.在Vue中操作DOM

  • Vue不建議在代碼中操作DOM,但是在復雜動畫效果,不操作DOM,光靠數據的綁定,是無法實現的。

    <div id="app">
        <div ref="hw" @click="handleClick">hello world</div>
    </div>
    var app = new Vue({
            el:"#app",
            methods:{
                handleClick:function () {
                    //指的是ref="hw"的DOM
                    divDom = this.$refs.hw;
                    console.log(divDom.innerHTML)
                }
            }
        })
    
  • 那么在組件中是如何應用ref,咱們定義一個計數功能:

    <div id="root">
        <!-- 父組件監聽change變化並交給 handleChange處理-->
        <counter @change="handleChange" ref="one"></counter>
        <counter @change="handleChange" ref="two"></counter>
        <div>{{total}}</div>
    </div>
    
    Vue.component("counter",{
        template:`<div @click="handleClick">{{number}}</div>`,
        data:function () {
            return {
                number:0
            }
        },
        methods:{
            handleClick:function () {
                this.number ++;
                //子組件需要向父組件傳遞事件,當當前組件數據發生變化時。
                this.$emit('change')
            }
        }
    });
    
    var vm = new Vue({
        // el限制一個vue實例的管理范圍。
        el:"#root",
        //total用來計算兩個counter組件內數據的和
        data:{
            total:0
        },
        methods:{
            handleChange:function () {
                //total求和
                this.total = this.$refs.one.number + this.$refs.two.number
            }
        }
    });
    

4.父子組件的數據傳遞

  • 父組件可以向子組件傳遞參數,但是子組件不能修改傳遞到子組件的參數,這就是單向數據流。

    • 方式1:子組件通過復制參數,從而只更改復制過來的參數
    <div id="root">
        <!--1.父組件向子組件傳遞名字為count的值-->
        <counter :count="0"></counter>
        <counter :count="5"></counter>
    </div>
    
    
    var counter = {
        // 2.子組件定義props接收count
        data:function(){
            return {
                // 3.既然子組件無法修改父組件傳來的參數
                // 那么number為復制傳過來的參數,咱們使用number
                number:this.count
            }
        },
    
        props:['count'],
        // 4.子組件使用復制過來的number,
        template:`<div @click="handleClick">{{number}}</div>`,
        methods:{
            handleClick:function () {
                // 並且還可以更改復制的number
                this.number ++
            }
        }
    };
    
    var vm = new Vue({
        // el限制一個vue實例的管理范圍。
        el:"#root",
        components:{
            counter:counter
        }
    });
    
    
    • 方式2:子組件向父組件傳遞事件
    <div id="root">
        <!--1.父組件向子組件傳遞名字為count的值-->
        <!--監聽inc事件,一旦觸發執行父組件handleIncrease函數-->
        <counter :count="0" @inc="handleIncrease"></counter>
        <counter :count="5" @inc="handleIncrease"></counter>
        <div>{{total}}</div>
    </div>
    
    var counter = {
        // 2.子組件定義props接收count
        data:function(){
            return {
                // 3.既然子組件無法修改父組件傳來的參數
                // 那么number為復制傳過來的參數,咱們使用number
                number:this.count
            }
        },
        props:['count'],
        // 4.子組件使用復制過來的number,
        template:`<div @click="handleClick">{{number}}</div>`,
        methods:{
            handleClick:function () {
                // 並且還可以更改復制的number
                this.number ++;
                // 5.子組件通過觸發事件,將觸發的inc事件傳遞給父組件
                this.$emit('inc',1)
            }
        }
    };
    
    var vm = new Vue({
        // el限制一個vue實例的管理范圍。
        el:"#root",
        data:{
          total:5,
        },
        components:{
            counter:counter
        },
        methods:{
            // 父組件定義函數
            handleIncrease:function (step) {
                // step 為子組件 $emit的第二個參數。
                this.total += step
            }
        }
    });
    

5.組件參數校驗與非props特性

  • 首先需要了解的是什么是props特性

    props特性其實就是,在父組件中傳入了參數,恰巧子組件在props也定義了該參數的校驗規則。並且子組件能使用該參數在template進行渲染
    
    <child content="hell world"></child>
    
    Vue.component('child',{
        // 子組件接收props
        props:{
            // 傳入content的類型
            // 方式1:content:[String,Number]
            // 方式2:
            content:{
                type:String,//要求傳入值類型
                required:false,//是否必填
                defaule:"default value",//默認值
                validator:function (value) {
                    // 傳入數據長度大於5
                    return (value.length > 5)
                }
            }
        },
       template:`<div>Child</div>`
    });
    var vm = new Vue({
        el:"#root",
    });
    
  • 非props特性

    父組件向子組件傳遞的是一個屬性,子組件並沒有聲明該屬性定義的內容。
    
    1.這樣子組件就不能使用該屬性在子組件template渲染。
    2.那么該屬性會在template定義的最外層標簽的標簽里,顯示.e.g.: <div content="hello">hello</div>
    

6.如何給組件綁定原生事件

  • 當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件

    <div id="root">
        <!--當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件-->
        <child @click="handleClick"></child>
    </div>
    
    
    
    Vue.component("child",{
        // 在標簽綁定事件時原生的事件
        template:"<div @click='handleClick'>Child</div>",
        methods:{
            //會觸發
            handleClick:function () {
                alert("click click")
            }
        }
    });
    var vm = new Vue({
        el:"#root",
        methods:{
            // 不會觸發
            handleClick:function () {
                alert("click")
            }
        }
    });
    
  • 那么如何觸發自定義事件?$emit

    Vue.component("child",{
        // 在標簽綁定事件時原生的事件
        template:"<div @click='handleClick'>Child</div>",
        methods:{
            //會觸發
            handleClick:function () {
                //通過$emit觸發自定義事件
                this.$emit("click")
            }
        }
    });
    
  • 但是這樣寫代碼冗余,過於繁瑣?通過添加事件修飾符.native

    <div id="root">
        <!--當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件-->
        <!--通過添加.native將該事件轉為原生click事件-->
        <child @click.native="handleClick"></child>
    </div>
    </body>
    <script>
        Vue.component("child",{
            // 在標簽綁定事件時原生的事件
            template:"<div>Child</div>",
        });
        var vm = new Vue({
            el:"#root",
            methods:{
                // 不會觸發
                handleClick:function () {
                    alert("click")
                }
            }
        });
    </script>
    

7.非父子組件傳值

  • 當把一個網頁拆分成多個部分,每個部分是一個組件

  • 如圖紅線,第二層的組件要跟第一層組件傳值可以通過

    父組件通過props向子組件傳值,子組件通過事件觸發,向父組件傳值
    
  • 如果第三層組件想傳值給第一層組件呢?

    如果直接傳值是不行了,只能通過第一層組件向第二層,第二層向第三層傳值,返回來也是一樣。
    
  • 但是這樣傳值相對比較復雜,比如出現如下圖③的情況就相當復雜了:

  • 那么如何解決呢?一般有2種方式解決非父子組件傳值,一種是vue官方提供的框架vuex,另一種使用發布訂閱模式(總線機制)。
  • 示例:兄弟組件傳值
<div id="exp">
    <!--實現點擊第一個子組件,里面值變成第二子組件值-->
    <!--實現點擊第二個子組件,里面值變成第一子組件值-->
    <!--這兩個child子組件是兄弟關系-->
    <child content="James"></child>
    <child content="Lucy"></child>
</div>
// 1.將bus屬性掛載到 Vue()實例里,以后創建的Vue()實例都有bus屬性
Vue.prototype.bus = new Vue();
Vue.component("child",{
    props:{
        content:String
    },
    // 1.1.在vue當中單向數據流,子組件不能改變父組件傳遞的內容
    // 所以定義一個data 返回復制后父組件傳的內容
    data:function(){
        return {
            selfContent:this.content
        }
    },
    //2.給子組件綁定一個點擊事件
    template:`<div @click="handleClick">{{selfContent}}</div>`,
    methods:{
        handleClick:function () {
            // 3.通過之前掛載的bus屬性,
            // 這個bus又是vue實例,所以也有$emit方法。
            // 通過$emit觸發change事件,同時攜帶當前標簽的內容
            this.bus.$emit('change',this.selfContent)
        }
    },
    // 4.mounted為一個生命周期鈎子,頁面渲染完執行周期函數mounted
    // 監聽這個bus.的改變(change事件)
    mounted:function () {
        // 5.底下function使this作用域發生,需要保存當前this
        var this_ = this;
        this.bus.$on('change',function (msg) {
            this_.selfContent = msg
        })
    }
});
var vm = new Vue({
    // el限制一個vue實例的管理范圍。
    el:"#exp",
});

8.Vue中的插槽

  • 插槽使用場景:當子組件內容是根據父組件傳遞過來的DOM內容進行顯示,可以使用插槽。
<div id="exp">
    <child>
        <p>Dell</p>
    </child>
</div>
<script>
    //當父組件child標簽內沒有內容,則會顯示<slot>默認內容</slot>
    Vue.component('child',{
        template:`
            <div>
                <p>Hello</p>
                <slot>默認內容</slot>
            </div>`
    });
    var vm = new Vue({
        el:"#exp",
    });

</script>
  • 具名插槽

    • 給插槽取一個名字。每個插槽能按照你的要求插入具體位置。
    <div id="exp">
        <body-content>
            <div class="header" slot="header">header</div>
            <div class="footer" slot="footer">footer</div>
        </body-content>
    </div>
    
    //當父組件child標簽內沒有內容,則會顯示<slot>默認內容</slot>
    Vue.component('body-content',{
        // 插槽設置默認值
        template:`
            <div>
                <slot name="header"><h1>default header</h1></slot>
                <div class="content">content</div>
                <slot name="footer"></slot>
            </div>`
    });
    var vm = new Vue({
        el:"#exp",
    });
    

9.Vue中的作用域插槽

  • 應用場景,當子組件做循環,其DOM結構由外部傳遞給子組件,子組件可以向插槽傳遞數據,父組件可以通過slot-scope接收數據並渲染。

    <div id="exp">
        <child>
            <!--父組件調用子組件給子組件傳入一個插槽-->
            <!--此插槽為作用域插槽,必須是template標簽-->
            <!--聲明slot-scope表示從子組件接收的數據都放在myData里-->
            <template slot-scope="myData">
                <!--通過myData調用每一項數據-->
                <li>{{myData.item}}</li>
            </template>
        </child>
    </div>
    
    <script>
        Vue.component('child',{
            data:function(){
              return {
                  list:[1,2,3,4,5]
              }
            },
            // 通過v-for形成插槽,並給每個插槽綁定數據 也就是item
            template:`
                <div>
                    <ul>
                        <slot
                            v-for="item of list"
                            :item=item
                        ></slot>
                    </ul>
                </div>`
        });
        var vm = new Vue({
            // el限制一個vue實例的管理范圍。
            el:"#exp",
        });
    </script>
    

10.動態組件與v-once指令

  • 動態組件

    <div id="exp">
        <!--根據type動態顯示相應組件-->
        <component :is="type"></component>
        <!--監聽點擊事件更改type數據-->
        <button @click="handleClick">change</button>
    </div>
    <script>
        Vue.component("child-one",{
            template:`<div>child one</div>`
        });
        Vue.component("child-two",{
            template:`<div>child two</div>`
        });
        var vm = new Vue({
            // el限制一個vue實例的管理范圍。
            el:"#exp",
            data:{
                type:'child-one'
            },
            methods:{
                handleClick:function () {
                    this.type = this.type === "child-one" ? "child-two":"child-one"
                }
            }
        });
    </script>
    
    • v-once

      看下面代碼,會有什么問題

      <div id="exp">
          <child-one v-if="type === 'child-one'"></child-one>
          <child-two v-if="type === 'child-two'"></child-two>
          <button @click="handleClick">change</button>
      </div>
      Vue.component("child-one",{
          template:`<div>child one</div>`
      });
      Vue.component("child-two",{
          template:`<div>child two</div>`
      });
      var vm = new Vue({
          // el限制一個vue實例的管理范圍。
          el:"#exp",
          data:{
              type:'child-one'
          },
          methods:{
              handleClick:function () {
                  this.type = this.type === "child-one" ? "child-two":"child-one"
              }
          }
      });
      

      每次點擊button按鈕其實相當於銷毀當前組件創建另一個組件,這樣頻繁的切換導致創建銷毀,挺耗費性能的,如果說我們定義的要切換的組件的內容相似,可以加一個v-once指令。通過v-once會將渲染的頁面放在內存中,這樣如果再切換回來直接從內存取,會提高靜態內容展示效率,只需在子組件template里添加v-once

      Vue.component("child-one",{
          template:`<div v-once>child one</div>`
      });
      Vue.component("child-two",{
          template:`<div v-once>child two</div>`
      });
      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM