ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 组件详解 >[success] 可在此处查看运行文档中的代码示例结果:[https://github.com/jianyaoo/Vue](https://github.com/jianyaoo/Vue) ## 基本使用 > 我们在注册一个组件的时候都会给组件起一个组件名,起组件名的两种方式为`kebab-case`(全部都是小写字母,中间用-连接)和`PascalCase`(首字母大写)。当时用连字符的时候,可能使用连字符的方式进行调用。如果使用首字母大小写的方式,两种方式都可以调用。 ### 全局注册组件 **<span style="padding-top:0px;display:inline-block;">注册方式</span>** 使用`Vue.component`方式注册的组件都为全局注册组件,全局注册组件可以在任何新创建的Vue根实例模板中 **<span style="padding-top:20px;display:inline-block;">代码实例</span>** ~~~html <h3>全局注册组件</h3> <div> <el-glob></el-glob> </div> ~~~ ~~~JavaScript Vue.component('el-glob',{ template:"<div>hello , component</div>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: <div> <h3>全局注册组件</h3> <div>hello , component</div> </div> </div> ### 实例内注册组件 **<span style="padding-top:0px;display:inline-block;">注册方式</span>** 实例内注册即在Vue的实例内使用`component`属性进行注册的方式。 **<span style="padding-top:20px;display:inline-block;">代码实例</span>** ~~~ <h3>实例内注册</h3> <div> <el-local></el-local> </div> ~~~ ~~~ // 声明一个组件的属性 var local = { template: "<div>这是一个实例内注册的组件</div>" } // 在根实例中调用组件 var vm = new Vue({ el:"#app", components:{ "el-local":local } }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: <div> <h3>实例内注册</h3> <div>这是一个实例内注册的组件</div> </div> </div> >[danger] component组件属性定义在哪个实例中,组件才可以在哪个实例中使用。而且子组件之间不可以直接调用,如果需要在子组件中调用另外一个子组件,需要在调用组件的属性中使用`component`属性 ### 特殊元素使用组件 **<span style="padding-top:0px;display:inline-block;">使用说明</span>** 有一些元素内只能使用特定的元素,例如`table`、`ul`、`ol`等,如果直接在这些元素内使用组件,组件会渲染到父级外面从而得不到自己想要的效果。使用`is`属性可以解决在这些特定组件上使用组件。 **<span style="padding-top:20px;display:inline-block;">代码实例</span>** ~~~ <h3>特殊元素使用组件</h3> <table> <tbody is="el-glob"> </tbody> </table> ~~~ ~~~ Vue.component('el-glob',{ template:"<th><td>hello , component</td></th>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: <div> <h3>特殊元素使用组件</h3> <div>hello , component</div> </div> </div> **<span style="padding-top:20px;display:inline-block;">代码说明</span>** 使用`is`后的代码结构如下: ``` <table> <th> <td>hello , component</td> <th> </table> ``` 在不使用`is`时的代码结构为: ``` <th> <td>hello , component</td> <th> <table> <tbody></tbody> </table> ``` ### 带数据的组件 **<span style="padding-top:0px;display:inline-block;">使用说明</span>** 在组件模板中如果使用变量,需要在组件中单独使用`data`属性。需要说明的是在组件中的`data`属性不是一个对象,而是一个可以返回一个对象的函数。 **<span style="padding-top:20px;display:inline-block;">代码实例</span>** ~~~ <h3>带数据的组件</h3> <div> <my-component></my-component> </div> ~~~ ~~~ Vue.component('my-component' , { data:function() { return{ message:"这是一个带数据的组件" } }, template:"<div>{{message}}</div>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: <div> <h3>带数据的组件</h3> <div>这是一个带数据的组件</div> </div> </div> ### 组件独立数据 一个独立组件的数据,应该声明在组件内部,只供当前组件一个可以调用,而不能定义在组件外面。容易引起当组件重复使用时发生错误的情况,如下代码所示: ~~~ <h3>组件独立数据</h3> <h5>反例</h5> <div> <el-data></el-data> <el-data></el-data> <el-data></el-data> </div> ~~~ ~~~ var data = { counter:0 } Vue.component("el-data",{ data:function() { return data ; }, template:"<button @click='counter++'>{{counter}}</button>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: 当点击第一个按钮时,第二个按钮的值和第三个按钮的值都会发生改变。 </div> 正确的实现代码应该如下: ~~~ Vue.component("el-data",{ data:function() { return { counter:0 }; }, template:"<button @click='counter++'>{{counter}}</button>" }) ~~~ ## 使用prop进行传值 通信组件即可以在不同的组件之间进行传值,传值的方式是使用`prop`属性。html中的属性大小写不敏感,如果使用驼峰法命名的属性在使用的时候需要用连接法。 ### 字符串数组传值 **<span style="padding-top:0px;display:inline-block;">简单传值</span>** ~~~html <h5>简单传值</h5> <div> <el-props message="我是父级的参数" my-count="参数内容"></el-props> </div> ~~~ ~~~ Vue.component("el-props" , { props:["message","myCount"], template:"<div>{{message}}+{{myCount}}</div>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: <h5>简单传值</h5> <div>我是父级的参数+参数内容</div> </div> **<span style="padding-top:20px;display:inline-block;">动态传值</span>** ~~~ <h5>动态传值</h5> <div> <input type="text" v-model="parentMessage"> <el-props :message="parentMessage"></el-props> </div> ~~~ ~~~ Vue.component("el-props" , { props:["message","myCount"], template:"<div>{{message}}</div>" }) ~~~ <div style="background:#333;color:#fff;padding:15px;"> 运行结果: div内的内容随着输入框中的内容发生变化而变化 </div> ### 单向数据流 所有的数据流都使得prop的数据由父级向下的一个单项绑定流动:即父级prop的更新会向下流动到子组件,但是子组件的prop更新不会影响到父级。这个就是prop数据的单向数据流。 >[info] 从父组件传下来的prop,每次父组件发生更新时,子组件的值都会自动刷新到最新值。所以一般不应该在子组件内部修改prop的值。 存在两种需要修改子组件prop的值得情况: **<span style="padding-top:20px;display:inline-block;">prop作为初始值</span>** 如果子组件接受到prop值后希望将prop值作为一个自己的参数使用,传递过来的prop值只是作为一个初始值。这种情况下应该在子组件内部定义一个变量来接收该参数。 ~~~ props:["counter"], data:function(){ return { count:this.counter } }, ~~~ **<span style="padding-top:20px;display:inline-block;">作为一个初始值且需要对prop值进行经常变化</span>** 当需要对prop值进行一定的逻辑处理的时候,就需要定义一个计算属性来接收prop值。 ~~~ props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } } ~~~ ### prop验证 当子组件接受到一个prop时,可以对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 } } } }) ~~~ ## 插槽