Vue的組件component(一)

Vue本身是基於組件化開發的,每個組件相當於一個Vue實例。Vue的組件部分搞清楚,是學好Vue的重要一步。

相關demo示例的github地址:vue-component

https://github.com/liwudi/Vue.git

1、Vue組件的全局註冊

要註冊一個全局組件,可以使用 Vue.component(tagName, options)。例如:

Vue.component('my-component', {
  // 選項
})
  • 1
  • 2
  • 3

使用的時候直接在dom中使用組件名。例如:

<my-component></my-component>
  • 1

下面是一個完整的帶有屬性傳遞的組件應用實例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <ol>
        <!--使用組件-->
        <todo-item
                v-for="item in todoList"
                v-bind:todo="item"
        ></todo-item>
    </ol>

</div>
<script>
    //定義一個最簡單的組件
    Vue.component('todo-item',{
        props:['todo'],
        template:'<li>name:{{todo.name}},age:{{todo.age}}</li>'
    });
    new Vue({
        el:'#app',
        data:{
            todoList:[{name:'張三',age:23},{name:'李四',age:24},{name:'王五',age:25}]
        }
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2、Vue組件的局部註冊

可以通過Vue實例/組件示例的實例選項 components 來註冊屬於他們自己的組件。

var Child = {
    template:"<p>我是中國人</p>"
}
new Vue({
    el:'#app',
    components: { 
        "my-comp": Child
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

一個完整的局部組件註冊的示例demo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">

    <todo-item></todo-item>
</div>
<script>
    var Child = {
        template: '<div>A custom component!</div>'
    };
    new Vue({
        el:'#app',
        components:{
            'todo-item': Child
        }
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3、組件中的data應該是函數

在new Vue()的實例的過程中,data可以是一個對象,但是在組件component中,data是一個函數。

下面的寫法在Vue中會報錯。

Vue.component('my-com',{
        template:'<span>{{message}}</span>',
        data: {
            message: 1
        }
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這個示例纔是正確的寫法:

Vue.component('my-com',{
   template:'<span>{{message}}</span>',
    data: function () {
        return {
            message: 1
        }
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4、組件應該是組合使用的

在react中,最外層是一個根組件,裏層的組件被一層層的嵌套在外層組件內,從而形成一個組件樹。

在 Vue 中,父子組件的關係可以總結爲 prop 向下傳遞,事件向上傳遞。父組件通過 prop 給子組件下發數據,子組件通過事件給父組件發送消息。

使用props傳遞數據的語法:

Vue.component('child', {
  // 聲明 props
  props: ['message'],
  // 就像 data 一樣,prop 也可以在模板中使用
  // 同樣也可以在 vm 實例中通過 this.message 來使用
  template: '<span>{{ message }}</span>'
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4_1、通過props進行屬性傳遞的demo

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <ol>
        <!--使用組件-->
        <my-com
                v-bind:todo="message"
        ></my-com>
    </ol>

</div>
<script>
    //定義一個最簡單的組件
    Vue.component('my-com',{
        props:['todo'],
        template:'<h3>{{todo}}</h3>'
    });
    new Vue({
        el:'#app',
        data:{
            message:'hello!'
        }
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

5、camelCase vs. kebab-case

兩者的區別是駝峯式命名規則,以及短橫線分隔式命名。

在JavaScript中,如果使用駝峯式命名camelCase。

由於在HTML中不區分大小寫,我們需要轉換成短橫線分隔式命名kebab-case。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <ol>
        <!--使用組件-->
        <todo-item
                my-todo="hello"
        ></todo-item>
    </ol>

</div>
<script>
    //定義一個最簡單的組件
    Vue.component('todo-item',{
        props:['myTodo'],
        template:'<h2>{{myTodo}}</h2>'
    });
    new Vue({
        el:'#app'
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

6、動態props

一般使用V-bind的方式,把一個屬性動態的綁定到props。

<todo-com v-bind:todo='message'></todo-com>
  • 1

如果沒有v-bind,就會展示message這個字符串;但是現在,展示的是在data中動態綁定的變量message的信息。

下面是一個動態綁定props的示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <ol>
        <!--使用組件-->
        <todo-item
                v-bind:my-todo="message"
        ></todo-item>
    </ol>

</div>
<script>
    //定義一個最簡單的組件
    Vue.component('todo-item',{
        props:['myTodo'],
        template:'<h2>{{myTodo}}</h2>'
    });
    new Vue({
        el:'#app',
        data: {
            message: 'hello world!'
        }
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

7、動態props,綁定一個對象作爲props傳遞給子組件。

比如一個對象是這樣的:

todo: {
  text: 'Learn Vue',
  isComplete: false
}
  • 1
  • 2
  • 3
  • 4

然後:

<todo-item v-bind="todo"></todo-item>
  • 1

等價於:

<todo-item
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"
></todo-item>
  • 1
  • 2
  • 3
  • 4

一個完整的示例demo如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">

    <todo-com v-bind="todo"></todo-com>
</div>
<script>
    //定義一個最簡單的組件
    Vue.component('todo-com',{
        props:['text','isComplete'],
        template:'<h2>I has {{isComplete ? "completed ":"not completed "}}{{text}}</h2>'
    });
    new Vue({
        el:'#app',
        data: {
            todo:{
                text: 'Learn Vue',
                isComplete: false
            }
        }
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

8、組件通信,props傳遞子組件的使用場景。

1、在子組件中獲取props的值,並且在子組件中需要改變這個值。

我們可以定義一個局部變量把props的值賦值給它。

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
  • 1
  • 2
  • 3
  • 4

2、在子組件中需要把這個props進行一定的處理,再進行使用。

定義一個計算屬性,處理 prop 的值並返回

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

9、props驗證

要指定驗證規則,需要用對象的形式來定義 prop,而不能用字符串數組:

Vue.component('example', {
  props: {
    // 基礎類型檢測 (`null` 指允許任何類型)
    propA: Number,
    // 可能是多種類型
    propB: [String, Number],
    // 必傳且是字符串
    propC: {
      type: String,
      required: true
    },
    // 數值且有默認值
    propD: {
      type: Number,
      default: 100
    },
    // 數組/對象的默認值應當由一個工廠函數返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

10、非props特性

所謂的非props特性是不用props申明,直接傳給子組件的一些特性。比如: class。

一般而言,父組件的非props特性對子組件的特性進行覆蓋和合並。

下面的示例中,如果父組件不使用class=’color2’,則數組顏色是紅色,如果使用了,則顏色爲綠色。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <style>
        .color1{
            color: red;
        }
        .color2{
            color: green;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <foo-component class="color2" v-bind:foo-message="fooMessage"></foo-component>
</div>
<script>
    var fooComponent = {
        props: ['fooMessage'],
        template: '<div class="color1"> {{ fooMessage }} </div>'
    };

     var vm = new Vue({
         components: {
            'foo-component': fooComponent
         },
         el: '#app',
         data: {
             fooMessage: 12345
         }
     });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

11、自定義事件(子組件向父組件傳值。)

使用 $emit(eventName) 觸發一個事件。

使用 $on(eventName) 接受一個事件。

但是一般使用的時候,使用 v-on:eventName = eventFunction 的方式定義事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <button-com v-on:parent="myEvent"></button-com>
</div>
<script>
    var Child = {
        template:'<button v-on:click="childEvent"> {{ num }} </button>',
        data: function () {
            return {
                num: 0
            }
        },
        methods:{
            childEvent: function () {
                this.num += 1;
                this.$emit("parent",this.num);
            }
        }
    };
    var vm = new Vue({
        el:'#app',
        data:{
            total: 0
        },
        components: {
            'button-com': Child
        },
        methods: {
            myEvent: function (data) {
                console.log(data);
            }
        }
    })
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

12、.sync修飾符

<comp :foo.sync="bar"></comp>
  • 1

等價於

<comp :foo="bar" @update:foo="val => bar = val"></comp>
  • 1

當子組件需要更新 foo 的值時,它需要顯式地觸發一個更新事件:

this.$emit('update:foo', newValue)
  • 1

下面是完整的demo

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
    <div>{{bar}}</div>
    <my-comp :foo.sync="bar"></my-comp>
</div>
<script>
    Vue.component('my-comp', {
        template: '<div @click="increment">{{copyFoo}}點我+1</div>',
        data: function() {
            return {copyFoo: this.foo}
        },
        props: ['foo'],
        methods: {
            increment: function() {
                this.$emit('update:foo', ++this.copyFoo);
            }
        }
    });
    new Vue({
        el: '#app',
        data: {bar: 0}
    });
</script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章