可复用性的组件详解
使用组件的原因
作用:提高代码的复用性
组件的使用方法
- 全局注册
<div id="app">
<my-componet></my-componet>
</div>
<!-- 对应的内容<div id="app"><div>我是一个全局组件</div></div> -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// Vue.component(tag, {
// template: '<div></div>'
// })
// 注册组件 第一个参数 标签名 第二个是要渲染的魔板
Vue.component('my-componet', {
template: '<div>我是一个全局组件</div>'
})
var app = new Vue({
el: '#app',
data: {
}
})
</script>
- 优点:所有的
Vue
实例都可以用 - 缺点:权限太大,容错率降低
- 局部注册
<div id="app" style="border:2px solid red ">
<!-- 全局组件 -->
<my-componet></my-componet>
<!-- 局部组件 -->
<app-componet></app-componet>
</div>
<!-- 对照试验 全局组件和局部组件 -->
<div id="bpp" style="border:2px solid green;margin-top:5px; ">
<!-- 全局组件 -->
<my-componet></my-componet>
<!-- app局部组件 只能在所注册的实例中使用 这里不会显示 -->
<app-componet></app-componet>
</div>
<!-- 对应的内容<div id="app"><div>我是一个全局组件</div></div> -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// Vue.component(tag, {
// template: '<div></div>'
// })
// 注册全局组件 第一个参数 标签名 第二个是要渲染的魔板
Vue.component('my-componet', {
template: '<div>我是一个全局组件</div>'
})
var app = new Vue({
el: '#app',
// 局部组件
components: {
'app-componet': {
template: '<div>我是app局部注册的一个组件组件</div>'
}
},
data: {
}
})
var bpp = new Vue({
el: '#bpp',
data: {
}
})
</script>
- 注意
vue
组件的模板在某些情况下会受到html
标签的限制,比如<table>
中只能还
有<tr>
,<td>
这些元素,所以直接在table
中使用组件是无效的,此时可以使用is
属性来挂载组件
<table>
<tbody is="my-component"></tbody>
</table>
组件使用的小技巧
- 推荐使用小写字母加进行命名(必须)
child,
mycomponnet
命名组件
- 推荐使用小写字母加进行命名(必须)
-
template
中的内容必须被一个DOM元
素包括 ,也可以嵌套
-
- 在组件的定义中,除了
template
之外的其他选项—data
,computed
,methods
- 在组件的定义中,除了
-
data
必须是一个方法data:function(){}
小实践:
-
<div id="app">
<!-- 推荐使用小写字母加进行命名(必须) -->
<my-component></my-component>
<!-- 点击任何一个 都会执行 可用组件方式解决 -->
<button @click="plus">{{count}}</button>
<button @click="plus">{{count}}</button>
<hr><br>
<!-- 组件方式解决 及 data必须是一个方法实践 两次点击的按钮 对象是不一致的 -->
<btn-component></btn-component>
<btn-component></btn-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count: 1
},
//组件
components: {
'my-component': {
// `template`中的内容必须被一个`DOM元`素包括 ,也可以嵌套
template: '<div><span>组件小技巧</span></div>'
},
'btn-component': {
template: '<button @click="count++">{{count}}</button>',
// 组件中的data`必须是一个方法
data: function() {
return {
count: 0
}
}
}
},
methods: {
plus: function() {
return this.count++
}
}
})
</script>
使用props传递数据 父亲向儿子传递数据
- 在组件中使用
props
来从父亲组件接收参数,注意,在props
中定义的属性,都可以在组件中直接使用
2. propps来自父级,而组件中data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
-
props
的值有两种,一种是字符串数组,一种是对象,本节先只讲数组 - 可以使用
v-bind
动态绑定父组件来的内容
先看个小栗子:
在父组件里向子组件传递消息:
<div id="app" style="border:2px solid green;height:200px;">
<h5 style="text-align:center">我是父组件</h5>
<child-component msg="我是来自父组件的内容"></child-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 一个父组件
var app = new Vue({
el: '#app',
// 定义一个子组件
components: {
'child-component': {
// 在组件中使用props来从父亲组件接收参数,
props: ['msg'],
// 注意,在props中定义的属性,都可以在 组件中直接使用
template: '<div style="border:2px solid red;height:70px;">{{msg}}</div>'
}
},
})
</script>
可以使用v-bind
动态绑定父组件来的内容:小栗子
在父组件里向子组件传递消息:
<div id="app" style="border:2px solid green;height:400px;">
<h5 style="text-align:center">我是父组件</h5>
<child-component msg="我是来自父组件的内容"></child-component>
<br>
<hr>使用v-bind进行数据动态绑定 把input中的msg传递给子组件
<input type="text" v-model="parentmsg">
<bind-component :msg="parentmsg"></bind-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 一个父组件
var app = new Vue({
el: '#app',
//父组件定义的内容
data: {
parentmsg: '今晚的月亮真圆啊'
},
// 定义一个子组件
components: {
'child-component': {
// 在组件中使用props来从父亲组件接收参数,
props: ['msg'],
// 注意,在props中定义的属性,都可以在 组件中直接使用
template: '<div style="border:2px solid red;height:70px;">{{msg}}</div>'
},
'bind-component': {
// 在组件中使用props来从父亲组件接收参数,
props: ['msg'],
// 注意,在props中定义的属性,都可以在 组件中直接使用
template: '<div style="border:2px solid red;height:70px;">{{msg}}</div>'
}
},
})
</script>
使用不使用v-bind
的区别 :
在父组件里向子组件传递消息:
<div id="app" style="border:2px solid green;height:400px;">
<h5 style="text-align:center">我是父组件</h5>
<child-component msg="我是来自父组件的内容"></child-component>
<hr><br>
<!-- v-bing 对照试验 传递数组 -->
v-bind对照试验 传递数组
<!-- msg.length 是7 -->
<child-component msg="[3,6,7]"></child-component>
<!-- 使用v-bind可以识别为数组 msg.length 是3 -->
<child-component :msg="[3,6,7]"></child-component>
<br>
<hr>使用v-bind进行数据动态绑定 把input中的msg传递给子组件
<input type="text" v-model="parentmsg">
<bind-component :msg="parentmsg"></bind-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 一个父组件
var app = new Vue({
el: '#app',
data: {
parentmsg: '今晚的月亮真圆啊'
},
// 定义一个子组件
components: {
'child-component': {
// 在组件中使用props来从父亲组件接收参数,
props: ['msg'],
// 注意,在props中定义的属性,都可以在 组件中直接使用
template: '<div style="border:2px solid red;height:70px;">{{msg}}</div>'
},
'bind-component': {
// 在组件中使用props来从父亲组件接收参数,
props: ['msg'],
// 注意,在props中定义的属性,都可以在 组件中直接使用
template: '<div style="border:2px solid red;height:70px;">{{msg}}</div>'
}
},
})
</script>
单向数据流
解释 : 通过 props
传递数据 是单向的了, 也就是父组件数据变化时会传递给子组
件,但是反过来不行。
目的 :是尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态。
应用场景: 业务中会经常遇到两种需要改变 prop
的情况
一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域
下可以随意使用和修改。这种情况可以在组件data
内再声明一个数据,引用父组件的prop
- 步骤一:注册组件
- 步骤二:将父组件的数据传递进来,并在子组件中用props接收
- 步骤三:将传递进来的数据通过初始值保存起来
小栗子:
<div id="app" style="border:2px solid green;height:400px;">
<my-component msg="我是父组件传递的数据"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 步骤一:注册组件
Vue.component('my-component', {
// 步骤二: 将父组件的数据传递进来, 并在子组件中用props接收
props: ['msg'],
template: ' <div>{{count}}</div>',
data: function() {
return {
// 步骤三: 将传递进来的数据通过初始值保存起来
// <!-- props的值可以通过this.xxx 直接进行获取-->
count: this.msg
}
},
})
var app = new Vue({
el: '#app',
data: {
}
})
</script>
另一种情况就是
prop
作为需要被转变的原始值传入。这种情况用计算属性就可以了
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props
接收
步骤三:将传递进来的数据通过计算属性进行重新计算
小栗子:
<div id="app" style="border:2px solid green;height:400px;">
<my-component msg="我是父组件传递的数据"></my-component>
<hr> <br>
<!-- 需求 :通过input中输入的数据动态改变div的宽度 -->
<!-- 传递的数据仅仅是一个数据 需要计算属性重新计算拼接 -->
<input type="text" v-model="width">
<width-component :width="width"></width-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 场景一 步骤一:注册组件
Vue.component('my-component', {
// 步骤二: 将父组件的数据传递进来, 并在子组件中用props接收
props: ['msg'],
template: ' <div>{{count}}</div>',
data: function() {
return {
// 步骤三: 将传递进来的数据通过初始值保存起来
// <!-- props的值可以通过this.xxx 直接进行获取-->
count: this.msg
}
},
})
// 场景二 步骤一:注册组件
Vue.component('width-component', {
// 步骤二: 将父组件的数据传递进来, 并在子组件中用props接收
props: ['width'],
template: ' <div :style="style"></div>',
data: function() {
return {
}
},
computed: {
style: function() {
// return 出来的就是直接拼接好的style
return {
width: this.width + 'px',
background: 'red',
height: '300px'
}
}
}
})
var app = new Vue({
el: '#app',
data: {
width: 0
}
})
</script>
数据验证
vue
组件中camelCased
(驼峰式) 命名与kebabcase
(短横线命名)
- 在
html
中,myMessage
和mymessage
是一致的,,因此在组件中的html
中使用必须使用kebabcase
(短横线)命名方式。在html
中不允许使用驼
峰!!!!!! (谨记) - 在组件中, 父组件给子组件传递数据必须用短横线。在
template
中,必
须使用驼峰命名方式,若为短横线的命名方式。则会直接保错。 - 在组件的
data
中,用this.XXX
引用时,只能是驼峰命名方式。若为短横线
的命名方式,则会报错。
小栗子:
<div id="app" style="border:2px solid green;height:400px;">
<!-- 会报错 Unknown custom element: myComponent 在组件中的`html`中使用必须使用`kebabcase`(短横线)命名方式。在`html`中不允许使用驼峰!!-->
<myComponent myMsg='lalalalal'></myComponent>
<!-- 正确方式 在组件中, 父组件给子组件传递数据必须用短横线。-->
<my-component my-msg='lalalalal'></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('myComponent', {
props: ['myMsg'],
// 在template中, 必须使用驼峰命名方式, 若为短横线的命名方式。 则会直接保错。
template: ' <div>{{abc}}</div>',
data: function() {
return {
// 在组件的data中,用this.XXX引用时,只能是驼峰命名方式。若为短横线的命名方式, 则会报错。
// abc: this.my - msg
// 正确的写法
abc: this.myMsg
}
},
})
var app = new Vue({
el: '#app',
data: {
a: '100',
b: '666',
c: true
}
})
</script>
验证的 type 类型可以是:
• String
• Number
•Boolean
• Object
• Array
•Function
栗子:
<div id="app" style="border:2px solid green;height:400px;">
<input type="text" v-model='d'>
<br>
<type-component :a='a' :b='b' :c='c' :d='d' :e='e' :f='f' :g='g'></type-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
// 数组验证
Vue.component('typeComponent', {
// 约定值的类型
props: {
a: String,
b: [String, Number],
// 必须是布尔类型 默认值是true typr required default
c: {
type: Boolean,
default: true
},
d: {
type: Number,
// 必选项为true 必须传值进行渲染
required: true
},
// 不向子组件传递 就会取默认值 default
e: {
type: Array,
default: function() {
return ['666e', 333]
}
},
//自定义验证函数
f: {
validator: function(value) {
return value > 10
}
},
//验证选项必须为function
g: {
type: Function
}
},
template: ' <div>{{a}}-----{{b}} -----{{c}}----{{d}} ------{{e[0]}}----{{f}} -----{{g}}</div>',
data: function() {
return {}
},
})
var app = new Vue({
el: '#app',
// 与上面的props中的选项对应
data: {
a: '100a',
// String或者是Number
b: '666b',
// 默认值为true
c: '',
// Missing required prop: "d"
d: 66622,
// 数组
e: [],
//自定义验证函数 value > 10 就是 88 > 10 就会渲染
f: 88,
// 验证类型为function
g: console.log("我是一个函数")
}
})
</script>
网友评论