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>

image

监听属性

监听属性,即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>

注意点

  1. template里面的内容最好包裹在一个标签内,比如div,不然可能显示不全。
  2. 父子组件的变量与函数不共享。
  3. 组件使用需要在某个vue对象绑定的标签内。
  4. 局部组件也可以在全局组件中定义和使用。

组件间通信

父传子(自定义属性)

子组件如果想要使用到父组件中的属性,可以自定义属性传入。

<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>

image

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>

image

posted @ 2022-06-29 17:27  Yume_Minami  阅读(80)  评论(0编辑  收藏  举报