Vue成神之路之實例和插槽

前言

記錄平時學到的知識,標題寫的大氣一點,也算是給自己一點鼓勵,希望在技術這條路可以遠走越遠,路越走越寬~

文中代碼地址

PS:如果對你有一點幫助,請順手給個小星星哦,鼓勵我繼續寫下去~

引入的文件文件說明

vue.js——開發版本:包含完整的警告和調試模式 vue.min.js——生產版本:刪除了警告,進行了壓縮

通過new Vue({...})生成的實例

通過new Vue({...})生成的實例可以在在構造器外部操作構造器內部的屬性選項或者方法。實例的作用就是給原生的或者其他javascript框架一個融合的接口或者說是機會,讓Vue和其他框架一起使用。

1. 實例

引入jquery,在DOM被掛載後修改裏邊的內容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="../assets/js/jquery.js"></script>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>實例</title>
</head>
<body>
    <h1>實例</h1>
    <hr>
    <div id="app">
        {{message}}
    </div>
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data:{
                message: 'Hello zaishuiyixia!'
            },
            mounted () {
                $('#app').html('我是jQuery!');
            }
        })
    </script>
</body>
</html>

現在頁面顯示是:我是jQuery,而不是Hello zaishuiyixia!了。

實例調用自定義方法:

在Vue的構造器裏寫一個add方法,然後用實例的方法調用它:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="../assets/js/jquery.js"></script>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>實例</title>
</head>
<body>
    <h1>實例</h1>
    <hr>
    <div id="app">
        {{message}}
    </div>
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data:{
                message: 'Hello zaishuiyixia!'
            },
            mounted() {
                $('#app').html('我是jQuery!');
            },
            methods: {
                add() {
                    console.log('通過實例調用了了add方法。')
                }
            }
        })

        app.add();
    </script>
</body>
</html>

打開控制檯可以看到打印出了:通過實例調用了了add方法。

2. 實例方法

**2.1

mount() 手動地掛載一個未掛載的實例。

這個方法返回實例自身,因而可以鏈式調用其它實例方法。

$mount方法可以用來掛載擴展:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>實例方法</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>實例方法</h1>
    <hr>
    <div id="app">
        {{message}}
    </div>
    <script type="text/javascript">
      var app = Vue.extend({
          template:`<p>{{message}}</p>`,
          data:function(){
              return {
                  message:'Hello ,I am zaishuiyixia!'
              }
          }
      })
      var vm = new app().$mount("#app")
    </script>
</body>
</html>

2.2 $destroy() 卸載/銷燬 實例方法

完全銷燬一個實例。清理它與其它實例的連接,解綁它的全部指令及事件監聽器。會觸發 beforeDestroy 和 destroyed 的生命週期函數。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>實例方法</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>實例方法</h1>
    <hr>
    <div id="app">
        {{message}}
        <br>    
    </div>
    <p><button onclick="destroy()">銷毀實例</button></p>
    <script type="text/javascript">
        var app = Vue.extend({
            template:`<p>{{message}}</p>`,
            data:function(){
                return {
                    message:'Hello ,I am zaishuiyixia!'
                }
            },
            destroyed() {
                console.log('實例已被銷燬。')
            }
        })
        var vm = new app().$mount("#app");

        function destroy(){
           vm.$destroy();
        }
    </script>
</body>
</html>

2.3 forceUpdate() 強制實例重新渲染方法

強制 Vue 實例重新渲染。注意它僅僅影響實例本身和插入插槽內容的子組件,而不是所有子組件。 會觸發beforeUpdate和updateed生命週期函數。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>實例方法</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>實例方法</h1>
    <hr>
    <div id="app">
        {{message}}
        <br>    
    </div>
    <p><button onclick="destroy()">銷毀實例</button></p>   
    <p><button onclick="forceUpdate()">強制實例重新渲染</button></p>
    <script type="text/javascript">
        var app = Vue.extend({
            template:`<p>{{message}}</p>`,
            data:function(){
                return {
                    message:'Hello ,I am zaishuiyixia!'
                }
            },
            beforeUpdate() {
                console.log('準備更新數據')
            },
            updated() {
                console.log('更新完成')
            },
            destroyed() {
                console.log('實例已被銷燬。')
            }
        })
        var vm = new app().$mount("#app");

        function destroy(){
           vm.$destroy();
        }

        function forceUpdate(){
           vm.$forceUpdate();
        }
    </script>
</body>
</html>

2.4 $nextTick() 當Vue構造器裏的data值被修改完成後會調用這個方法,也相當於一個鉤子函數,和構造器裏的updated生命週期作用很像。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>實例方法</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>實例方法</h1>
    <hr>
    <div id="app">
        {{message}}
        <br>    
    </div>
    <p><button onclick="destroy()">銷毀實例</button></p>   
    <p><button onclick="forceUpdate()">強制實例重新渲染</button></p>
    <p><button onclick="tick()">更新數據</button></p>
    <script type="text/javascript">
        var app = Vue.extend({
            template:`<p>{{message}}</p>`,
            data:function(){
                return {
                    message:'Hello ,I am zaishuiyixia!'
                }
            },
            beforeUpdate() {
                console.log('準備更新數據')
            },
            updated() {
                console.log('更新完成')
            },
            destroyed() {
                console.log('實例已被銷燬。')
            }
        })
        var vm = new app().$mount("#app");

        function destroy(){
           vm.$destroy();
        }

        function forceUpdate(){
           vm.$forceUpdate();
        }

        function tick(){
            vm.message="update message info ";
            vm.$nextTick(function(){
                console.log('message更新完後我被調用了');
            })
        }
    </script>
</body>
</html>

3. 實例事件

vm.

emit觸發。回調函數會接收所有傳入事件觸發函數的額外參數。

$on 在構造器外部添加事件:

app.$on('reduce',function(){
    console.log('執行了reduce()');
    this.num--;
});

$on接收兩個參數,第一個參數是調用時的事件名稱,第二個參數是一個匿名方法。

事件可以由vm.$emit觸發:

//外部調用內部事件
function reduce(){
    app.$emit('reduce');
}

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>實例事件</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>Example Event Demo</h1>
    <hr>
    <div id="app">
        <p>{{num}}</p>
        <button @click="add">add</button>
        
    </div>
    <p><button onclick="reduce()">reduce</button></p>
     
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data:{num:1},
            methods:{
                add:function(){
                    this.num++;
                }
            }
        })

        //實例事件
        app.$on('reduce',function(){
            console.log('執行了reduce()');
            this.num--;
        });
    </script>
</body>
</html>

vm.$once( event, callback )監聽一個自定義事件,但是隻觸發一次,在第一次觸發之後移除監聽器。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>實例事件</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>Example Event Demo</h1>
    <hr>
    <div id="app">
        <p>{{num}}</p>
        <button @click="add">add</button>  
    </div>
     <p><button onclick="reduce()">reduce</button></p>
     <p><button onclick="reduceOnce()">reduceOnce</button></p>
     <p><button onclick="off()">off</button></p>
     

    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data:{num:1},
            methods:{
                add() {
                    this.num++;
                }
            }
        })

        //實例事件
        app.$on('reduce',function(){
            console.log('執行了reduce()');
            this.num--;
        });

        //只使用一次的實例方法
        app.$once('reduceOnce',function(){
            console.log('只執行一次的方法');
            this.num--;
        });
    </script>
</body>
</html>

vm.$off( [event, callback] )移除自定義事件監聽器:

  1. 如果沒有提供參數,則移除所有的自定義事件監聽器;
  2. 如果只提供了事件,則移除該自定義事件事件所有的監聽器;
  3. 如果同時提供了事件與回調,則只移除這個回調的監聽器。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>實例事件</title>
    <script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
    <h1>Example Event Demo</h1>
    <hr>
    <div id="app">
        <p>{{num}}</p>
        <button @click="add">add</button>  
    </div>
     <p><button onclick="reduce()">reduce</button></p>
     <p><button onclick="reduceOnce()">reduceOnce</button></p>
     <p><button onclick="off()">off</button></p>
     

    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data:{num:1},
            methods:{
                add() {
                    this.num++;
                }
            }
        })

        //實例事件
        app.$on('reduce',function(){
            console.log('執行了reduce()');
            this.num--;
        });

        //只使用一次的實例方法
        app.$once('reduceOnce',function(){
            console.log('只執行一次的方法');
            this.num--;
        });

        //關閉事件
        function off(){
            app.$off('reduce');
        }

        //外部調用內部事件
        function reduce(){
            app.$emit('reduce');
        }

        function reduceOnce(){
            app.$emit('reduceOnce');
        }
    </script>
</body>
</html>

4. 插槽-slot

插槽,也就是slot,是組件的一塊HTML模板,這塊模板顯示不顯示、以及怎樣顯示由父組件來決定。 實際上,一個slot最核心的兩個問題在這裏就點出來了,是顯示不顯示和怎樣顯示。

由於插槽是一塊模板,所以,對於任何一個組件,從模板種類的角度來分,其實都可以分爲非插槽模板和插槽模板兩大類。

非插槽模板指的是html模板,比如'div、span、ul、table'這些,非插槽模板的顯示與隱藏以及怎樣顯示由組件自身控制;插槽模板是slot,它是一個空殼子,因爲它的顯示與隱藏以及最後用什麼樣的html模板顯示由父組件控制。但是插槽顯示的位置卻由子組件自身決定,slot寫在組件template的什麼位置,父組件傳過來的模板將來就顯示在什麼位置

4.1 默認插槽 | 匿名插槽:

默認插槽,也可以叫它匿名插槽,它不用設置name屬性。它會作爲所有未匹配到插槽的內容的統一出口。

一個組件中只能有一個該類插槽。相對應的,具名插槽就可以有很多個,只要名字(name屬性)不同就可以了

父組件:

<template id="tmp">
    <div class="father">
        <h3>這裏是父組件</h3>
        <child>
            <div class="tmpl">
              <span>菜單1</span>
              <span>菜單2</span>
              <span>菜單3</span>
              <span>菜單4</span>
              <span>菜單5</span>
              <span>菜單6</span>
            </div>
        </child>
    </div>
</template>

子組件:

<template id="tmp2">
    <div class="child">
        <h3>這裏是子組件</h3>
        <slot></slot>
    </div>
</template>

在這個例子裏,因爲父組件在裏面寫了html模板,那麼子組件的匿名插槽這塊模板就是下面這樣。也就是說,子組件的匿名插槽被使用了,是被下面這塊模板使用了。

<div class="tmpl">
  <span>菜單1</span>
  <span>菜單2</span>
  <span>菜單3</span>
  <span>菜單4</span>
  <span>菜單5</span>
  <span>菜單6</span>
</div>

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>Mixins Option</title>
    <style>
        .father {
            background: #ccc;
        }
        .child {
            background: green;
        }
    </style>
</head>
<body>
    <h1>內置組件Slot</h1>
    <hr>
    <div id="app">
        <father></father>
    </div>

    <template id="tmp">
        <div class="father">
            <h3>這裏是父組件</h3>
            <child>
                <div class="tmpl">
                  <span>菜單1</span>
                  <span>菜單2</span>
                  <span>菜單3</span>
                  <span>菜單4</span>
                  <span>菜單5</span>
                  <span>菜單6</span>
                </div>
            </child>
        </div>
    </template>

    <template id="tmp2">
        <div class="child">
            <h3>這裏是子組件</h3>
            <slot></slot>
        </div>
    </template>

    <script type="text/javascript">
        var child = {
            template: '#tmp2'
        }

        var father = {
            template:'#tmp',
            components: {
                "child": child
            }
        }

        var app=new Vue({
            el:'#app',
            data:{
               
            },
            components:{
                "father": father
            }
        })
    </script>
</body>
</html>

打開控制檯可以查看效果,父組件以灰色背景填充,子組件都以綠色填充。

4.2 具名插槽 :

匿名插槽沒有name屬性,所以是匿名插槽,那麼,插槽加了name屬性,就變成了具名插槽。具名插槽可以在一個組件中出現N次,出現在不同的位置。下面的例子,就是一個有兩個具名插槽和一個匿名插槽的組件,這三個插槽被父組件用同一套css樣式顯示了出來,不同的是內容上略有區別。

父組件:

<template id="tmp">
  <div class="father">
    <h3>這裏是父組件</h3>
    <child>
      <div class="tmpl" slot="up">
        <span>菜單1</span>
        <span>菜單2</span>
        <span>菜單3</span>
        <span>菜單4</span>
        <span>菜單5</span>
        <span>菜單6</span>
      </div>
      <div class="tmpl" slot="down">
        <span>菜單-1</span>
        <span>菜單-2</span>
        <span>菜單-3</span>
        <span>菜單-4</span>
        <span>菜單-5</span>
        <span>菜單-6</span>
      </div>
      <div class="tmpl">
        <span>菜單->1</span>
        <span>菜單->2</span>
        <span>菜單->3</span>
        <span>菜單->4</span>
        <span>菜單->5</span>
        <span>菜單->6</span>
      </div>
    </child>
  </div>
</template>

子組件:

<template id="tmp2">
  <div class="child">
    <!--具名插槽 -->
    <slot name="up"></slot>
    <h3>這裏是子組件</h3>
    <!--具名插槽-->
    <slot name="down"></slot>
    <!--匿名插槽-->
    <slot></slot>
  </div>
</template>

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>具名插槽</title>
    <style>
        .father {
            background: #ccc;
        }
        .up {
            background: green;
        }
        .down {
            background: red;
        }
        .tmpl {
            background: blue;
        }
        .child {
            background: yellow;
        }
    </style>
</head>
<body>
    <h1>具名插槽</h1>
    <hr>
    <div id="app">
        <father></father>
    </div>

    <template id="tmp">
        <div class="father">
        <h3>這裏是父組件</h3>
        <child>
          <div class="up" slot="up">
            <span>菜單1</span>
            <span>菜單2</span>
            <span>菜單3</span>
            <span>菜單4</span>
            <span>菜單5</span>
            <span>菜單6</span>
          </div>
          <div class="down" slot="down">
            <span>菜單-1</span>
            <span>菜單-2</span>
            <span>菜單-3</span>
            <span>菜單-4</span>
            <span>菜單-5</span>
            <span>菜單-6</span>
          </div>
          <div class="tmpl">
            <span>菜單->1</span>
            <span>菜單->2</span>
            <span>菜單->3</span>
            <span>菜單->4</span>
            <span>菜單->5</span>
            <span>菜單->6</span>
          </div>
        </child>
      </div>
    </template>

    <template id="tmp2">
        <div class="child">
            <!--具名插槽 -->
            <slot name="up"></slot>
            <h3>這裏是子組件</h3>
            <!--具名插槽-->
            <slot name="down"></slot>
            <!--匿名插槽-->
            <slot></slot>
        </div>
    </template>

    <script type="text/javascript">
        var child = {
            template: '#tmp2'
        }

        var father = {
            template:'#tmp',
            components: {
                "child": child
            }
        }

        var app=new Vue({
            el:'#app',
            data:{
               
            },
            components:{
                "father": father
            }
        })
    </script>
</body>
</html>

打開瀏覽器可以看到,父組件通過html模板上的slot屬性關聯具名插槽。沒有slot屬性的html模板默認關聯匿名插槽。

4.3 作用域插槽 | 帶數據的插槽:

官方叫它作用域插槽,實際上,對比前面兩種插槽,可以叫它帶數據的插槽。意思就是前面兩種,都是在組件的template裏面寫:

匿名插槽
<slot></slot>
具名插槽
<slot name="up"></slot>

但是作用域插槽要求,在slot上面綁定數據。也就是你得寫成大概下面這個樣子:

<slot name="up" :data="data"></slot>
 export default {
    data: function(){
      return {
        data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
      }
    },
}

插槽最後顯示不顯示是看父組件有沒有在child下面寫模板,像下面那樣:

<child>
   html模板
</child>

寫了的話,插槽就會在瀏覽器上顯示內容,內容就是html該有的模樣,沒寫,插槽就是空殼子,什麼也沒有。

作用域插槽跟單個插槽和具名插槽的區別,因爲單個插槽和具名插槽不綁定數據,所以父組件提供的模板一般要既包括樣式又包括內容。而作用域插槽綁定了一套數據,父組件可以拿來用,所以父組件只需要提供樣式,內容可以顯示子組件插槽綁定的數據。

父組件:

<template id="tmp">
  <div class="father">
    <h3>這裏是父組件</h3>
    <!--第一次使用:用flex展示數據-->
    <child>
      <template slot-scope="user">
        <div class="tmpl">
          <span v-for="item in user.data">{{item}}</span>
        </div>
      </template>

    </child>

    <!--第二次使用:用列表展示數據-->
    <child>
      <template slot-scope="user">
        <ul>
          <li v-for="item in user.data">{{item}}</li>
        </ul>
      </template>

    </child>

    <!--第三次使用:直接顯示數據-->
    <child>
      <template slot-scope="user">
       {{user.data}}
      </template>

    </child>

    <!--第四次使用:不使用其提供的數據, 作用域插槽退變成匿名插槽-->
    <child>
      我就是模板
    </child>
  </div>
</template>

子組件:

<template>
  <div class="child">

    <h3>這裏是子組件</h3>
    // 作用域插槽
    <slot  :data="data"></slot>
  </div>
</template>

 export default {
    data: function(){
      return {
        data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
      }
    }
}

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>作用域插槽</title>
    <style>
        .father {
            background: #ccc;
        }
        .child {
            background: green;
        }
    </style>
</head>
<body>
    <h1>作用域插槽</h1>
    <hr>
    <div id="app">
        <father></father>
    </div>

    <template id="tmp">
        <div class="father">
            <h3>這裏是父組件</h3>
            <!--第一次使用:用flex展示數據-->
            <child>
                <template slot-scope="user">
                    <div class="tmpl">
                        <span v-for="item in user.data">{{item + '、'}}</span>
                    </div>
                </template>
            </child>

            <!--第二次使用:用列表展示數據-->
            <child>
              <template slot-scope="user">
                <ul>
                  <li v-for="item in user.data">{{item}}</li>
                </ul>
              </template>
            </child>

            <!--第三次使用:直接顯示數據-->
            <child>
                <template slot-scope="user">
                    {{user.data}}
                </template>

            </child>

            <!--第四次使用:不使用其提供的數據, 作用域插槽退變成匿名插槽-->
            <child>
                我就是模板
            </child>
        </div>
    </template>

    <template id="tmp2">
        <div class="child">

            <h3>這裏是子組件</h3>
            <!--作用域插槽-->
            <slot  :data="data"></slot>
        </div>
    </template>

    <script type="text/javascript">
        var child = {
            template: '#tmp2',
            data: function(){
                return {
                    data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
                }
            }
        }

        var father = {
            template:'#tmp',
            components: {
                "child": child
            }
        }

        var app=new Vue({
            el:'#app',
            data:{
               
            },
            components:{
                "father": father
            }
        })
    </script>
</body>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章