Vue.js 组件

Vue.js 组件

组件是Vue.js最推崇的,也是最强大的功能之一,核心目标是为了可重用性高,减少重复性的开发。我们可以把组件代码按照template、style、script的拆分方式,放置到对应的.vue文件中。
Vue.js的组件可以理解为预先定义好行为的ViewModel类。一个组件可以预定义很多选型,但最核心的是以下几个:

  • 模板 —— 模板生命力数据和最终展现给用户的DOM之间的映射关系。
  • 初始数据 —— 一个组件的初始数据状态。对于可复用的组件来说,通常是私有的状态。
  • 接受的外部参数 —— 组件之间通过参数来进行数据的传递和共享。参数默认是单向绑定(由上至下),但也可以显示声明为双向绑定。
  • 方法 —— 对数据的改动操作一般都在组建的方法内进行。可以通过v-on 指令将用户输入事件和组件方法进行绑定。
  • 生命周期钩子函数 —— 一个组件会触发多个生命周期钩子函数,比如created、attached、destroyed等。在这些钩子函数中,我们可以封装一些自定义的逻辑。和传统的MVC相比,这可以理解为Controller的逻辑被分散到了这些钩子函数中。

基础

注册

1、全局注册

Vue.component('didi-component',DIDIComponent)

如上所示,第一个参数是注册组件的名称;第二个参数是组件的构造参数,它可以是Function,也可以是Object。

  • Function —— DIDIComponent可以是用Vue.extend()创建的一个组件构造器。
var MyComponent = Vue.extend({
	// 选项..
})
  • Object —— DIDIComponent传入选项对象,Vue.js在背后自动调用Vue.extend()。
// 在一个步骤中扩展与注册
Vue.component('didi-component',{
	template: '<div>A custom component!</div>'
})

组件在注册之后,便可以在父实例的模块中以自定义元素<didi-component>的形式使用。要确保在初始化根实例之前注册了组件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <didi-component></didi-component>
    </div>
</body>
<script>
    Vue.component('didi-component',{
        template: '<div>A custom component!</div>'
    })
    new Vue({
        el: '#example'
    })
</script>
</html>

在这里插入图片描述
注: 组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。可以用实例选项replace决定是否替换自定义元素。
2、局部注册
不需要每个组件都全局注册,可以让组件只能用在其他组件内。我们可以用实例选项components注册。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <didi-component></didi-component>
    </div>
</body>
<script>
    var Child = Vue.extend({
        template: '<div>i am child!</div>',
        replace: true
    })
    var Parent = Vue.extend({
        template: '<div><p>i am parent</p><br><child></child></div>',
        components: {
            // <didi-component>只能用在父组件模板内
            'child': Child
        }
    })
    // 创建根实例
    new Vue({
        el: '#example',
        components: {
            'didi-component': Parent
        }
    })
</script>
</html>

在这里插入图片描述
注:如果你在模板中尝试写了多个跟元素时,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题。

数据传递

总结下来,Vue.js 组件之间有三种数据传递方式:

  • props
  • 组件通信
  • slot
    1、props
    "props"是组件数据的一个字段,期望从父组件传下来数据。因为组件实例的作用域是孤立的,这意味着不能并且不应该在子组件的模板内直接引用父组件的数据,所以子组件需要显式地用props选项来获取父组件的数据。props选项可以是字面量,也可以是表达式,还可以绑定修饰符。
    1)字面量语法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <child msg="hello"></child>
    </div>
</body>
<script>
    Vue.component('child',{
        // 声明props
        props: ['msg'],
        // prop可以用在模板内
        // 可以用`this.msg`设置
        template: '<span>{{msg}},DDFE!</span>'
    })
    new Vue({
        el: '#example'
    })
</script>
</html>

在这里插入图片描述
HTML特征不区分大小写。名字形式为camelCase的props用作特性时,需要转换为kebab-case形式(短横线隔开)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <child my-component="hello!"></child>
    </div>
</body>
<script>
    var myComponent = Vue.extend({
        props: ['myComponent'],
        template: '<span>{{myComponent}},DDFE!</span>'
    })
    Vue.component('child',myComponent)
    new Vue({
        el: '#example'
    })
</script>
</html>

在这里插入图片描述
2)动态语法
类似于用v-bind将HTML特性绑定到一个表达式,我们也可以用v-bind将动态props绑定到父组件的语法。每当父组件的数据变化时,该变化也会传到给子组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <didi-props></didi-props>
    </div>
</body>
<script>
    var Child = Vue.extend({
        // 声明props
        props: ['didiProps'],
        template: '<div>{{didiProps}} DDFE!</div>'
    })
    var Parent = Vue.extend({
        template: '<div><p>i am parent</p><br/><child :didi-props="hello"></child></child></div>',
        data: function(){
            return {'hello':'hello,'}
        },
        components: {
            // <child>只能用在父组件模板内
            'child': Child
        }
    })
    // 创建根实例
    new Vue({
        el: '#example',
        components: {
            'didi-props': Parent
        }
    })
</script>
</html>

在这里插入图片描述
3)prop验证
组件可以为props指定验证要求。当组件给其他人使用时,可以确保其他人正确地使用组件。此时prop的值是一个对象。

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    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 ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

type 可以是下列原生构造函数中的一个:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
    额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。
    2、组件通信
    尽管子组件可以用this.$parent访问它的父组件,父组件有一个数组this.$children,包含它所有的子元素,根实例的后代可以用this.$root访问根实例,不过子组件应当避免直接依赖父组件的数据,尽管显式地使用props传递数据。另外,在子组件中修改父组件地状态是非常糟糕地做法,因为:
  • 父组件与子组件紧密地耦合
  • 只看父组件,很难理解父组件的状态,因为它可能被任意子组件修改!在理想情况下,只有组件自己能修改其状态。
    因为作用域是有层次的,所以我们可以在作用域链上传递事件。通常来说,选择事件传递方法,一个好的经验规则就是:查看触发事件的作用域。
  • $on() —— 监听事件
  • $emit() —— 把事件沿着作用域向上派送
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值