Vue 元件基礎

liaohui5發表於2019-03-03

官方教程: https://cn.vuejs.org/v2/guide

宣告元件

let myComponent = Vue.extend({
    template : '#my',
    // 此時的 #my 是id="my"的template標籤
});

// 可以簡化為
let myComponent = {
    template : '#my',
    data(){
        // 此處的data必須是一個函式
    }
};
複製程式碼

註冊元件(全域性元件, 區域性元件)

// 全域性元件: 一次註冊在所有的vue例項中(都能夠使用
Vue.component('my-component',{
    template : '#my-component',
    data () {
        // 此處的data必須是一個函式    
    },
});

// 區域性元件: 只能在某一個vue例項中使用
const vm = new Vue({
    'el' : '#app',
    components : {
        'my-component' : {
            template : '#my',
            data() { 
                // 此處的data必須是一個函式
            }
        },
    }
});
複製程式碼

注: 為了保證各個元件的相互獨立性,所有的元件中的data必須是一個函式

元件之間的通訊

  • 父元件 => 子元件: props
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue study</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- templates -->
<template id="my">
    <div>
        <p>這是本元件自己的資料: {{selfData}}</p>
        <p>這是父元件的資料: {{msg}}</p>
    </div>
</template>
<!-- /templates -->


<!-- 使用元件 -->
<div id="app">
    <my-component :msg="message"></my-component>
</div>


<script>
    // 1.宣告一個元件
    let myComponent = Vue.extend({
        template: '#my',
        props: ["msg"],
        // props 不僅僅可以是一個陣列,也可以是一個物件
        data() {
            return {
                selfData: "hello Vue",
            };
        },
    });
    
    
/** props 支援的型別=========================
 1. 簡單語法
  Vue.component('props-demo-simple', {
    props: ['size', 'myMessage']
  })
  2. 物件語法,提供校驗
  Vue.component('props-demo-advanced', {
    props: {
      // 檢測型別
      height: Number,
      // 檢測型別 + 其他驗證
      age: {
        type: Number,
        default: 0,
        required: true,
        validator: function (value) {
          return value >= 0
        }
      }
    }
  });
==================================*/

    // 2.在Vue例項中來註冊元件
    const vm = new Vue({
        el: '#app',
        data: {
            message: 'hello world',
        },
        components: {
            // 註冊一個區域性元件
            'my-component': myComponent,
            // 注: 此時必須使用 - 分割單詞,或者全部小寫,不能使用駝峰式寫法
        }
    });
</script>
<!--
    父元件 => 子元件: 在子元件中使用父元件的資料
    1. 宣告一個元件
    2. 註冊元件(全域性或者區域性元件都可以通訊)
    3. 使用元件(my-component), 並在使用時繫結一個屬性 :msg
    4. 在子元件中用 props 來獲取繫結的屬性   props : ["msg"],
    5. 測試,看是否能夠成功傳遞值
-->
</body>
</html>
複製程式碼
  • 子元件 => 父元件: 釋出訂閱
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue study</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 使用元件 -->
    <my-component :msg="message" @custom_event="changeData"></my-component>
</div>

<!-- templates -->
<template id="my">
    <div>
        <p>{{msg}}</p>
        <p>{{selfData}}</p>
        <!-- <button @click="$emit('custom_enevt','args')">點我改變父元件的資料</button> -->
        <!-- 如果覺得這種行內的觸發滿足不了複雜的邏輯需求,你也可以把這個觸發寫到這個元件的方法中 -->
         <button @click="triggerParent(10)">點我改變父元件的資料</button>
    </div>
</template>

<script>
    // 宣告一個元件
    let myComponent = Vue.extend({
        template: '#my',
        props: ["msg"],
        data() {
            return {
                selfData: 'hello Vue',
            };
        },
        methods : {
            triggerParent(val){
                // 觸發父元件並傳遞一個引數,此時的val是click呼叫時傳遞的引數
                this.$emit('custom_event', val);
            },
        },
    });

    const vm = new Vue({
        el: '#app',
        data: {
            message: 'hello world',
        },
        methods: {
            changeData (val) {
                // 把message變成一個隨機數連線上子元件傳遞的引數
                this.message = val + Math.ceil(Math.random()*100);
            },
        },
        components: {
            // 註冊一個區域性元件
            'my-component': myComponent,
        }
    });
</script>
<!--
由於vue為了保證各個元件的獨立性,所以將各個元件的資料流向做成那單向資料流,
而這樣,就只能父元件改變子元件的內容,而不能子元件改變父元件的內容
所以為了能夠在子元件中改變父元件的資料,只有使用自定義事件系統

1. 宣告一個元件  let myComponent = Vue.extend({...});
2. 註冊一個元件(全域性,區域性都行)
3. 使用元件
    3.1) 繫結一個屬性     :msg="message"  子元件可以用 props 來獲取繫結的屬性
    3.2) 繫結一個自定義事件 @custom_event="changeData" 此時的custom_event是事件名稱,changeData是methods中的方法
    3.3) 子類想改變父類的資料,可以用$emit('事件名稱')來觸發父元件的事件,然後由父元件決定改變的規則,從而達到單向資料流的目的
    3.4) 觸發父類自定義事件
        3.4.1) 行內觸發
            <button @click="$emit('custom_enevt','args')">點我改變父元件的資料</button> 此時的args是引數
        3.4.2) 使用方法觸發
            <button @click="triggerParent(10)">點我改變父元件的資料</button>
            methods : {
                 triggerParent(val){
                     // 觸發父元件並傳遞一個引數,此時的val是click呼叫時傳遞的引數
                     this.$emit('custom_event', val);
                  },
            }
-->
</body>
</html>
複製程式碼
  • 元件巢狀的情況
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue元件巢狀</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <style>
        .cmpt1, .cmpt2 {
            color: #ffffff;
            padding: 15px;
        }

        .cmpt1 {
            background: #272822;
        }

        .cmpt2 {
            background: #265a88;
        }
    </style>
</head>
<body>
<div id="app">
    <my-component @custom_event="changeData" :msg="message"></my-component>
</div>

<!-- templates -->
<template id="my">
    <div>
        <one :msg="msg" :name="name"></one>
        <two :msg="msg" @test_event="changeMess"></two>
    </div>
</template>

<!--one-->
<template id="one">
    <div class="cmpt1">
        <p>這是元件1</p>
        <p>這是二級傳遞: hello {{msg}}!!! </p>
        <p>這是三級傳遞: what's your name? my name is {{name}}</p>
    </div>
</template>

<!--two-->
<template id="two">
    <div class="cmpt2">
        <p>這是元件2</p>
        <p> hello {{msg}} </p>
        <p>
            <button @click="changePrentData(10)">點我改變父元件資料</button>
        </p>
    </div>
</template>


<script>
    // 宣告一個子元件
    let one = Vue.extend({
        template: '#one',
        props: ["msg", "name"],
    });

    // 宣告一個子元件
    let two = Vue.extend({
        template: '#two',
        props: ["msg"],
        methods: {
            changePrentData(val) {
                let m = Math.ceil(Math.random() * val);
                // this.$emit('custom_event', m);
                this.$emit('test_event', m);
            }
        },
    });

    // 宣告一個父元件
    let myComponent = Vue.extend({
        template: '#my',
        props: ["msg"],
        methods: {
            changeMess(val){
                this.$emit('custom_event',val);
            }
        },
        components: {
            'one': one,
            'two': two
        },
        data() {
            return {
                name: 'Tom',
            };
        }
    });

    const vm = new Vue({
        el: '#app',
        data: {
            message: 'world',
        },
        methods: {
            changeData(val) {
                this.message = "這是改變後的message,喜歡嗎? " + val + " 是點選是傳遞的引數";
            }
        },
        components: {
            // 註冊一個區域性元件
            'my-component': myComponent,
        }
    });
</script>
<!--
    元件巢狀時,最底層的元件想要與最頂層的元件通訊,必須一層一層向上傳遞
-->
</body>
</html>
複製程式碼
  • 例項 模態框
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>蒙版效果</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        html, body {
            width: 100%;
            height: 3000px;
            /* 為了測試滾動 */
        }

        #alert-panel {
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            position: absolute;
            top: 0;
            left: 0;
            /*display: none;*/
        }

        #alert-panel #login {
            width: 500px;
            height: 300px;
            background: #000000;
            position: fixed;
            top: 50%;
            left: 50%;
            margin-left: -250px;
            margin-top: -180px;
        }

        #close-alert-panel {
            background: #000;
            color: #ffffff;
            border: none;
            width: 30px;
            height: 30px;
            float: right;
        }

        #close-alert-panel:hover {
            background: #f00;
        }
    </style>

    <!--javascript-->
    <script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">
    <!-- 當點選button的時候,顯示模態框,在模態框中點選關閉按鈕時,關閉模態框 -->
    <button id="btn" @click="showDialog">點選登陸</button>

    <modal :is-hide-dialog="!isHide" @close="closeModal"></modal>
</div>

<template id="dialog">
    <div id="alert-panel" v-show="isHideDialog">
        <div id="login">
            <button id="close-alert-panel" @click="$emit('close')">&times;</button>
        </div>
    </div>
</template>

<script>
    // 宣告一個元件
    let modal = Vue.extend({
        template: '#dialog',
        props: ["isHideDialog"],
    });

    const vm = new Vue({
        el: '#app',
        data: {
            isHide: true,
        },
        methods: {
            showDialog() {
                this.isHide = false;
            },
            closeModal() {
                this.isHide = true;
            }
        },
        components: {
            'modal': modal
        }
    });
</script>
</body>
</html>
複製程式碼
  • 父元件呼叫子元件的方法

注: 如果ref放在元件上,那麼通過$refs拿到的不是元件的dom而是這個元件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue study</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">
    <!-- 注: 如果ref放在元件上,那麼通過$refs拿到的不是元件的dom而是這個元件 -->
    <load ref="load"></load>
</div>

<!--templates-->
<template id="load">
    <div v-if="isShow">
        <p>玩命載入中...</p>
    </div>
</template>

<!-- JavaScript -->
<script>
    let load = Vue.extend({
        template: '#load',
        data () {
            return {
                isShow: true,
            }
        },
        methods: {
            hide(){
                this.isShow = false;
                console.log("我被呼叫了,這個元件已經被隱藏了");
            }
        },
    });

    const vm = new Vue({
        el: '#app',
        components: {
            "load": load,
        },
        mounted () {
            // 當vm例項掛載的時候,就呼叫子元件的方法,隱藏載入元件
            this.$refs.load.hide();
        }
    });

</script>
</body>
</html>

複製程式碼
  • 在子元件中加工父元件傳遞的值

預設在子元件中不能修改父元件傳遞的值,如果非要 加工父元件傳遞過來的資料,可以使用 computed 屬性或者 data() 來加工父元件傳遞的值,此種方式雖然能夠加工了父元件 傳遞的資料,但是不會改變父元件的資料,保證了各個元件的獨立性(單向資料流)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue study</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>


<div id="app">
    <my-comp :name="message"></my-comp>
</div>

<!--templates-->
<template id="my">
    <div>
        <p>父元件原資料: {{name}}</p>
        <p>改變後的資料: {{myName}}</p>
        <p>改變後的資料: {{myName2}}</p>
    </div>
</template>

<!-- JavaScript -->
<script>
    // make a component
    let myComponent = Vue.extend({
        template: '#my',
        props: ["name"],
        // 要求: 在子元件中,將父元件傳遞的值拼接一個隨機數
        // 方式一:使用計算屬性來改變父元件傳遞的值
        computed:{
            myName(){
                return this.name + Math.random();
            }
        },
        // 方式二:使用data()方法來改變父元件傳遞的值(區域性變數)
        data(){
            return {
                "myName2" :this.name + Math.random(),
            }
        },
    });

    const vm = new Vue({
        el: '#app',
        data: {
            message: 'hello world',
        },
        components: {
            // register a local component
            "my-comp": myComponent,
        },
    });

</script>
</body>
</html>

複製程式碼

相關文章