当前位置:   article > 正文

vue自定义组件总结_:change:prop

:change:prop

组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树。

一、四个核心组成

1、props 2、自定义事件 event 3、插槽及作用域插槽 slot 4、组件方法 method。
任何组件均离不开以上4点,我们在开发过程中,以这4点入手,封装我们想要的组件。

以element-ui table组件为例

Table Attributes 指的是 props
props data 显示的数据

Table Events 指的是 自定义事件
自定义事件 selection-change 当选择项发生变化时会触发该事件

Table Slot 插槽
append 插入至表格最后一行之后的内容,如果需要对表格的内容进行无限滚动操作,可能需要用到这个 slot。若表格有合计行,该 slot 会位于合计行之上。

Table-column Scoped Slot 插槽及作用域插槽 slot
Table-column 是 el-table-column组件,有一个默认插槽 自定义列的内容,参数为 { row, column, $index }


我们通常这样使用

1

2

3

4

5

6

7

8

9

<el-table-column

    fixed="right"

    label="操作"

    width="100">

      <template slot-scope="scope">

        <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>

        <el-button type="text" size="small">编辑</el-button>

      </template>

</el-table-column>

slot-scope="scope" 父组件通过scope访问子组件作用域。

Table Methods 指的是 组件方法
组件方法 clearSelection 用于多选表格,清空用户的选择 。 组件方法是通过 添加ref 索引,获取组件实例后调用。this.$refs.组件ref标识.组件方法

 以上是组件核心概念。

二、组件注册

1、组件名

组件名应该始终是多个单词的,根组件 App 除外

这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。

单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)

混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题,这也是横线连接命名同样完全可取的原因

使用 kebab-case
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>

1

Vue.component('my-component-name', { /* ... */ })

使用 PascalCase
当使用 PascalCase (驼峰式命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的

1

Vue.component('MyComponentName', { /* ... */ })


2、全局注册

以上方法都属于全局注册, 也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中, 比如

HTML

1

2

3

4

5

<div id="app">

  <component-a></component-a>

  <component-b></component-b>

  <component-c></component-c>

</div>

JS

Vue.component('component-a', { /* ... */ })

Vue.component('component-b', { /* ... */ })

Vue.component('component-c', { /* ... */ })

new Vue({ el: '#app' })

在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用.

3、局部注册


如果不需要全局注册,或者是让组件使用在其它组件内,可以用选项对象的 components 属性实现局部注册, 这里不做详述。

三、父子组件通信


在vue组件通信中其中最常见通信方式就是父子组件之中的通信,而父子组件的设定方式在不同情况下又各有不同。最常见的就是父组件为控制组件子组件为视图组件。父组件传递数据给子组件使用,遇到业务逻辑操作时子组件触发父组件的自定义事件。无论哪种组织方式父子组件的通信方式都是大同小异

父组件到子组件通讯

父组件到子组件的通讯主要为:子组件接受使用父组件的数据,这里的数据包括属性和方法(String, Number, Boolean, Object, Array, Function)。vue提倡单项数据流,因此在通常情况下都是父组件传递数据给子组件使用,子组件触发父组件的事件,并传递给父组件所需要的参数

通过 props 传递数据 (推荐)

父子通讯中最常见的数据传递方式就是通过props传递数据,就好像方法的传参一样,父组件调用子组件并传入数据,子组件接受到父组件传递的数据进行验证使用

props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义校验和设置默认值

prop 的定义应该尽量详细,至少需要指定其类型

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

<!-- 父组件 -->

<template>

    <div>

        <my-child :parentMessage="parentMessage"></my-child>

    </div>

</template>

<script>

    import MyChild from '@components/common/MyChild'

    export default {

        components: {

            MyChild

        },

        data() {

            return {

                parentMessage: "我是来自父组件的消息"

            }

        }

    }

</script>

<!-- 子组件 -->

<template>

    <div>

        <span>{{ parentMessage }}</span>

    </div>

</template>

<script>

    export default {

        props: {

            parentMessage: {

                type: String,

                default'默认显示的信息'

                // require: true // 必填

            }

        }

    }

</script>

子组件到父组件通讯

子组件到父组件的通讯主要为父组件如何接受子组件之中的数据。这里的数据包括属性和方法(String, Number, Boolean, Object, Array, Function)

通过 $emit 传递父组件数据 (推荐)

与父组件到子组件通讯中的$on配套使用,可以向父组件中触发的方法传递参数供父组件使用

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

<!-- 父组件 -->

<template>

    <div>

        <my-child @childEvent="parentMethod"></my-child>

    </div>

</template>

<script>

    import MyChild from '@components/common/MyChild'

    export default {

        components: {

            MyChild

        },

        data() {

            return {

                parentMessage: '我是来自父组件的消息'

            }

        },

        methods: {

            parentMethod({ name, age }) {

                console.log(this.parentMessage, name, age)

            }

        }

    }

</script>

<!-- 子组件 -->

<template>

    <div>

        <h3>子组件</h3>

    </div>

</template>

<script>

    export default {

        mounted() {

            this.$emit('childEvent', { name: 'zhangsan', age:  10 })

        }

    }

</script>

不推荐的通信方式
this.$parent
this.$children
this.$refs

四、兄弟组件通信

1、vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,它是响应式的,状态发生变化,组件会更新。

vuex实现兄弟组件通信非常简单,组件A引用vuex数据,组件B通过方法改变vuex数据,vuex状态是响应式的,数据放生变化,组件A会更新。

2、eventBus又称为事件总线

在vue中可以使用eventBus来作为沟通桥梁, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。

初始化

首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它。

我们在src/components/目录下新建文件bus.js。

1

2

import Vue from 'vue'

export default new Vue()

发送事件

假设你有两个兄弟组件: ComA和ComB,ComA发送消息给ComB。

ComA这样

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

<template>

    <div>

        <button @click="sendMsg">给组件B发送消息</button> 

    </div>

</template>

<script>

import bus from './bus'

export default {

    name: 'comA',

    data () {

        return {

             

        }

    },

     

    methods: {

        sendMsg() {

            bus.$emit('fromA', {

                phone: 13800138000

            })

        }

    }

}

</script>

很显然,ComA中使用bus.$emit(事件名,数据);向事件中心注册发送事件。

接收事件

ComB接受ComA发送过来的消息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<template>

    <div>

        <p>{{fromA}}</p>

    </div>

</template>

<script>

import bus from './bus'

export default {

    name: 'comB',

    data () {

        return {

            fromA: '',

        }

    },

    mounted() {

        bus.$on('fromA', param => {

            this.fromA = param.phone;

        })

    }

}

</script>

于是,当ComA发送了一个手机号码phone给ComB时,comB就会接收并显示。

父组件

在父组件中调用ComA和ComB两个兄弟组件。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<template>

  <div>

    <comA></comA>

    <comB></comB>

  </div>

</template>

<script>

import ComA from './ComA.vue'

import ComB from './ComB.vue'

export default {

    components: {

       ComA,

       ComB

    },

}

</script>


五、多层级组件通讯

1、vuex
2、eventBus
3、provide / inject

provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// 父级组件提供 'foo'

var Provider = {

  provide: {

    foo: 'bar'

  },

  // ...

}

// 子组件注入 'foo'

var Child = {

  inject: ['foo'],

  created () {

    console.log(this.foo) // => "bar"

  }

  // ...

}

六、作用域插槽

有时让插槽内容能够访问子组件中才有的数据是很有用的。例如,设想一个带有如下模板的 <current-user> 组件:

1

2

3

<span>

  <slot>{{ user.lastName }}</slot>

</span>

我们可能想换掉备用内容,用名而非姓来显示。如下:

1

2

3

<current-user>

  {{ user.firstName }}

</current-user>

然而上述代码不会正常工作,因为只有 <current-user> 组件可以访问到 user 而我们提供的内容是在父级渲染的。

为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个 attribute 绑定上去:

1

2

3

4

5

<span>

  <slot v-bind:user="user">

    {{ user.lastName }}

  </slot>

</span>

绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字:

1

2

3

4

5

<current-user>

  <template v-slot:default="slotProps">

    {{ slotProps.user.firstName }}

  </template>

</current-user>

在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。

七、组件的方法

组件方法,就是我们写组件时,在methods选项里边定义的一些方法,他通常是对数据的CURD。
element-ui我们常用的有

this.$refs[formName].resetFields(); form表单重置
this.$refs.[treeName].getCheckedKeys() tree 返回目前被选中的节点的 key 所组成的数组

八、vue 语法糖

1、v-model

v-model可以实现数据双向的绑定,自动为组件添加了props 名为 value 和 自定义事件 名为 input。

1

<input type="text" v-model="name">

实际上,上面的代码是下面代码的语法糖。

1

<input  v-bind:value="name"  v-on:input="name=$event.target.value"/>

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

Vue.component('base-checkbox', {

  model: {

    prop: 'checked',

    event: 'change'

  },

  props: {

    checked: Boolean

  },

  template: `

    <input

      type="checkbox"

      v-bind:checked="checked"

      v-on:change="$emit('change', $event.target.checked)"

    >

  `

})

现在在这个组件上使用 v-model 的时候:

1

<base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。

2、.sync 修饰符

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

1

this.$emit('update:title', newTitle)

然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:

1

2

3

4

<text-document

  v-bind:title="doc.title"

  v-on:update:title="doc.title = $event"

></text-document>

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

1

<text-document v-bind:title.sync="doc.title"></text-document>

九、组件选项推荐顺序

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

<script>

  export default {

    el: '#app'// 只在由 new 创建的实例中遵守。

     

    // 全局感知

    name: 'name'// 组件name

    parent: VueInstance, // 指定父实例

    // 组件类型

    functional: false// 没有data 实例 没有上下文

    // 模板修改器

    delimiters: ['${''}'], // 分隔符变成了 ES6 模板字符串的风格

    comments: false// 当设为 true 时,将会保留且渲染模板中的 HTML 注释。默认行为是舍弃它们。

    // 模板依赖

    components: {}, // 子组件

    directives: {}, // 自定义指令

    filters: {}, // 自定义过滤器

    // 组合

    extends: CompA, // 扩展另一个组件 和 mixins 类似

    mixins: [tableEvents], // 混入选项对象, 混入实例对象可以像正常的实例对象一样

    // 接口

    inheritAttrs: true,

    model: { // 自定义组件在使用 v-model 时定制 prop 和 event

      prop: 'checked',

      event: 'change'

    },

    propsData: { // 只用于 new 创建的实例中。   创建实例时传递 props。

    },

    // 本地状态

    data: () => ({ // 本地状态

    }),

    computed: { // 计算属性

    },

    // 事件 生命周期钩子

    watch: {

    },

    // 生命周期钩子

    beforeCreate() {

    },

    created() {

    },

    beforeMount() {

    },

    mounted() {

    },

    beforeUpdate() {

    },

    updated() {

    },

    activated() {

    },

    deactivated() {

    },

    beforeDestroy() {

    },

    destroyed() {

    },

    // 非响应式的属性 (不依赖响应系统的实例属性)

    methods() {

    },

    // 渲染 (组件输出的声明式描述)

    template: '<div>demo</div>'// 渲染模板

    render: function (createElement) {

      return createElement(

        'h' this.level,   // 标签名称

        this.$slots.default // 子节点数组

      )

    },

    renderError (h, err) { // 只在开发者环境下工作。

      return h('pre', { style: { color: 'red' }}, err.stack)

    }

     

  }

</script>

十、组件样式推荐使用CSS 作用域

1

2

3

<style scoped>

    

</style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/229234
推荐阅读
相关标签
  

闽ICP备14008679号