Vue组件
目录
计算属性和监听属性
计算属性
现有需求,把用户输入的字符串首字母变大写并显示,如果使用普通的方法去显示,那么每次其他地方的数据更新时,这个方法也会执行,就会显得多余,所以就需要用到计算属性。
计算属性可以把函数当成属性使用,函数的返回值就是属性值,计算属性只有在它的相关依赖发生改变时才会重新求值。
computed: {
myfunc() {
return
}
}
使用并验证:
<div id="app">
普通方法:<input type="text" v-model="name1">--->{{ firstUpper() }}<br>
计算属性:<input type="text" v-model="name2">--->{{ getNameUpper }}<br>
普通输入框:<input type="text" v-model="name3">--->{{ name3 }}<br>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
name1: '',
name2: '',
name3: ''
},
methods: {
firstUpper() {
console.log('函数执行了')
return this.name1.substr(0, 1).toUpperCase() + this.name1.substr(1)
}
},
computed: {
getNameUpper() {
console.log('计算属性')
return this.name2.substr(0, 1).toUpperCase() + this.name2.substr(1)
}
}
})
</script>
监听属性
监听属性,即vue对象中data中的变量发生了变化就会执行对应函数,函数名要用变量名。
watch:{
变量名(){
}
}
简单使用:
<div id="app">
<input type="text" v-model="name">
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
name: '',
},
watch:{
name(){
console.log('name值发生了变化')
}
}
})
</script>
全局组件和局部组件
定义组件的大概结构:
{
template: '', // 组件内容
data() { // 相当于vue对象中的data
return { // return里面写变量
name: 'tom'
}
},
methods:{ // 其余的定义与vue对象一样
}
}
全局组件
全局组件即整个页面中都可以使用的组件。
定义全局组件
<div id="app01">
<h1>app01</h1>
<child></child>
</div>
<div id="app02">
<h1>app02</h1>
<child></child>
</div>
<script>
Vue.component('child', {
template: `
<div>
<h2>我是全局组件</h2>
<p>name值为{{ name }} <button @click="windowOut">弹窗</button></p>
</div>
`,
data() {
return {
name: 'tom'
}
},
methods: {
windowOut(){
alert(this.name)
}
}
})
const vm1 = new Vue({
el: '#app01',
})
const vm2 = new Vue({
el: '#app02',
})
</script>
局部组件
局部组件只能在定义它的vue对象绑定的标签中使用。
定义局部组件
<div id="app01">
<child></child>
</div>
<script>
const vm = new Vue({
el: '#app01',
components: {
child: {
template: `
<div>
<h2>我是局部组件</h2>
<p>name值为{{ name }} <button @click="windowOut">弹窗</button></p>
</div>
`,
data() {
return {
name:'tom'
}
},
methods:{
windowOut(){
alert(this.name)
}
}
}
}
})
</script>
注意点
- template里面的内容最好包裹在一个标签内,比如div,不然可能显示不全。
- 父子组件的变量与函数不共享。
- 组件使用需要在某个vue对象绑定的标签内。
- 局部组件也可以在全局组件中定义和使用。
组件间通信
父传子(自定义属性)
子组件如果想要使用到父组件中的属性,可以自定义属性传入。
<div id="app01">
<!-- 自定义属性后传入父组件的属性 -->
<child :myname="name"></child>
</div>
<script>
const vm = new Vue({
el: '#app01',
data: {
name: 'tom'
},
components: {
child: {
template: `
<div>
<p>父组件name值为{{ myname }}</p>
</div>
`,
props:['myname',] // 声明自定义属性
}
}
})
</script>
限制自定义属性类型
只能传入指定的数据类型,不然报错,报错但还是可以正常使用。
props:{
'myname': String,
'myage': Number,
}
子传父(自定义事件)
父组件想要使用子组件的属性,就需要自定义事件。
<div id="app01">
<p>子组件的属性值:{{ name }}</p>
<child @myevent="getSon"></child>
</div>
<script>
const vm = new Vue({
el: '#app01',
data: {
name: ''
},
methods:{
getSon(sonData){
this.name=sonData
}
},
components: {
child: {
template: `
<div>
<button @click="putData">点我给父组件传值</button>
</div>
`,
data() {
return {
sonName:'tom'
}
},
methods: {
putData() {
// 触发自定义事件myevent,myevent绑定的函数需要几个参数,就可以传几个参数
this.$emit('myevent', this.sonName)
}
}
}
}
})
</script>
ref属性
普通标签设置ref属性上,拿到的是原生节点,可以执行原生dom操作;
组件设置ref属性,拿到的是组件对象,通过组件对象就可以实现父传子、子传父;
普通标签设置
<div id="app01">
<p ref="pp">我是一个p标签</p>
<button @click="changeTag">点我改变p标签</button>
</div>
<script>
const vm = new Vue({
el: '#app01',
methods:{
changeTag(){
// this.$refs['pp']就是p标签
this.$refs['pp'].innerText = '修改后的p标签'
}
},
})
</script>
组件设置
子传父
直接点属性名获取。
<div id="app01">
<child ref="cc"></child>
<button @click="changeTag">点我改变子组件属性</button>
</div>
<script>
Vue.component('child', {
template:`
<div>
<p>子组件属性:{{ name }}</p>
</div>
`,
data() {
return {
name:'tom'
}
}
})
const vm = new Vue({
el: '#app01',
methods:{
changeTag(){
// this.$refs['cc']就是子组件对象
this.$refs['cc'].name = 'jim'
}
},
})
</script>
父传子
通过给子组件函数传参数。
<div id="app01">
<child ref="cc"></child>
<button @click="changeTag">点我改变子组件属性</button>
</div>
<script>
Vue.component('child', {
template:`
<div>
<p>子组件属性:{{ name }}</p>
</div>
`,
data() {
return {
name:'tom'
}
},
methods: {
getFather(d) {
this.name = d
}
}
})
const vm = new Vue({
el: '#app01',
methods:{
changeTag(){
this.$refs['cc'].getFather('jim')
}
},
})
</script>
数据总线
数据总线实现不同层级的不同组件之间的通信。
大概使用:
// 定义一个数据总线,其实就是一个vue对象
var bus = new Vue()
// 一个组件接收,监听
Vue.component('child1', {
// 可以写在挂载后执行的钩子函数中,实时接收
mounted() {
bus.$on('waitData', (res) => {
// res即发送来的数据
})
}
})
// 一个组件发送
Vue.component('child2', {
methods: {
postData() {
// 监听那边需要几个参数就传几个
bus.$emit('waitData', res)
}
}
})
实战:
<div id="app01">
<h3>child1组件</h3>
<child1></child1>
<hr>
<h3>child2组件</h3>
<child2></child2>
</div>
<script>
const bus = new Vue()
Vue.component('child1', {
template:`
<p>child2发送过来的数据:{{ name }}</p>
`,
data() {
return {
name:''
}
},
mounted() {
bus.$on('waitData', (res) => {
this.name = res
})
}
})
Vue.component('child2', {
template: `
<button @click="postData">点我发送数据</button>
`,
methods: {
postData() {
bus.$emit('waitData', 'abcd')
}
}
})
const vm = new Vue({
el: '#app01',
methods:{
},
})
</script>
动态切换组件
动态切换组件主要通过component配合is属性,决定哪一个组件显示。
<component is='组件名'></component>
实战:
<div id="app01">
<button @click="name='home'">首页</button>
<button @click="name='message'">信息</button>
<button @click="name='setting'">设置</button>
<br>
<component :is="name"></component>
</div>
<script>
Vue.component('home', {
template: `
<p>首页</p>
`,
})
Vue.component('message', {
template: `
<p>信息页面</p>
`,
})
Vue.component('setting', {
template: `
<p>设置页面</p>
`,
})
const vm = new Vue({
el: '#app01',
data:{
name:'home'
}
})
</script>
slot插槽
slot插槽作用:在组件中插入内容。需要组件中添加slot标签。
单个插槽
<div id="app01">
<child>
<p>插入的内容</p>
</child>
</div>
<script>
Vue.component('child', {
template: `
<div>
<p>child组件开头</p>
<slot></slot>
<p>child组件结束</p>
</div>
`,
})
const vm = new Vue({
el: '#app01',
})
</script>
多个插槽
多个插槽需要给slot标签添加name属性值,根据属性值插入。
<div id="app01">
<child>
<p style="color: aqua" slot="bb">我插入bb插槽</p>
<p style="color: red" slot="aa">我插入aa插槽</p>
</child>
</div>
<script>
Vue.component('child', {
template: `
<div>
<p>child组件开头</p>
<slot name="aa"></slot>
<slot name="bb"></slot>
<p>child组件结束</p>
</div>
`,
})
const vm = new Vue({
el: '#app01',
})
</script>