Vue中的vm.$refs及监视属性(watch/ computed)

3,220 阅读1分钟

1. vm.$refs

  • 定义:被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例;
  1. 定义MyRef组件,分别展示引用指向DOM元素和组件两种情况
  • 其中Inner组件就是即将用来被引用的组件
  • 组件包括一个button按钮(DOM元素),一个引入的Inner组件,两个分贝绑定show1、show2事件的button按钮(主要用来点击展示获取的DOM元素和组件的结果)
<template>
  <div class="box">
    <h2>MyRef</h2>
    <button ref="btn1" @click="doClick">按钮</button>
    <!-- 原生事件绑定在根元素 -->
    <Inner ref="comp1" @click.native="doClick"/>
    <button @click="show1">展示效果(获取DOM元素)</button>
    <button @click="show2">展示效果(获取组件)</button>
  </div>
</template>

<script>
import Inner from './01_Inner.vue'
export default {
    components:{
        Inner
    },
    methods:{
        show1(){
            console.dir(this.$refs.btn1)
        },
        show2(){
            console.dir(this.$refs.comp1)
            console.dir(this.$refs.comp1.getData())
        },
        doClick(){
            alert('点击了')
        }
    }
}
</script>
  1. 定义Inner组件
  • 组件很简单,组件只包含一个getData()方法
<template>
  <div>Inner</div>
</template>

<script>
export default {
    methods:{
        getData(){
            return 999;
        }
    }
}
</script>
  1. 引用指向的就是 DOM 元素和引用就指向组件实例的结果展示
  • 引用指向的就是 DOM 元素

image.png

  • 引用就指向组件实例

image.png

补充知识点

在MyRef组件的<Inner ref="comp1" @click.native="doClick"/>代码,向组件绑定事件时,需要加上标识.native(比如click事件就是@click.native),就可以实现点击整个组件执行对应的事件代码;

2. watch/ computed监视属性

2.1 watch属性
  • watch的监听变量必须是data中的;
  • 无法监听数组值为基本数据类型时的值的变化;
  • 可以设置属性deep: true,来实现深度监听;
<template>
    <div class="box">
        <h2>02Watch</h2>
        <input v-model="name">
        {{ name }}
        <hr />
        <input v-model="obj.name">
        {{ obj.name }}
        <hr />
        {{ arr }}
        <button @click="arr[1] = 99">改变数组元素</button>}
    </div>
</template>

<script>
export default {
    // 1.watch的监听变量必须是data中的
    data() {
        return {
            name: 'Green',
            obj: {
                name: 'green'
            },
            // 无法监听数组值为基本数据类型时的值的变化
            arr: [1, 2, 3]
        }
    },
    methods: {
        loadData() {
            console.log('初始化数据...');
        }
    },
    watch: {
        name(newV, oldV) {
            console.log('值:', newV, oldV)
        },
        obj: {
            deep: true,
            handler(newV, oldV) {
                console.log('深度监视:', newV, oldV);
                // 保证初始 调用一次 , 后续变更, 继续调用
                this.loadData();
            }
        },
        arr: {
            deep: true,
            handler(newV, oldV) {
                console.log('深度监视2:', newV, oldV)
            }
        },
    }
}
</script>
  • 初始界面

image.png

  • 当输入值变化时

image.png

image.png

这里要注意

  • 点击改变数组元素按钮,页面数组值没有发生变化。证明无法监听数组值为基本数据类型时的值的变化;
  • 如果对象中有__ob__属性,证明该元素实现了监视,没有证明该元素没有被监视;
  • 可以使用与deep属性同级的immediate属性,设置为 true可以实现初始 调用一次的效果 , 而且后续变更, 继续调用;
补充知识,动态添加watch属性

点击按钮给指定input组件动态添加watch属性

<button @click="addWatch">动态加入watch</button>
<hr />
<input v-model="text">
{{ text }}

在methods中定义addWatch方法(注意定义方法的代码格式)

addWatch() {
    this.$watch('text', function (newV) {
        console.log('text变化了', newV)
    });
}
2.2 computed监视属性
  • 必须只有this.xxx相关的属性变更才会被监视,触发计算属性
<template>
    <div class="box">
        <h2>03_Computed</h2>
        <input type="text" v-model="n1"> +
        <input type="text" v-model="n2"> +
        <input type="text" v-model="n3">
        = {{ calc }}
    </div>
</template>
computed: {
        calc() {
            return parseInt(this.n1)
            + parseInt(this.n2)
            + parseInt(this.n3) 

        }
    }

效果如下图

image.png

  • 使用computed属性实现多选框选择功能,具体功能描述:
  1. 全选: 选中的话,子项都选中,反之,都不选中,子项每次勾选或取消, 同步全选状态;
  2. 全选变更同步子项,子项变更计算有一项不为true,全选就不勾;
<template>
    <div class="box">
        <h2>03_Computed</h2>
        <input type="checkbox" v-model="calcSelectAll">全选
        <ul>
            <li v-for="(item, i) in arr">
                <input type="checkbox" v-model="item.checked"> {{ item }}
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    data() {
        return {
            arr: [
                    { checked: true, text: "小木" },
                    { checked: true, text: "小明" },
                    { checked: true, text: "小红" },
            ]
        }
    },
    computed: {
        calcSelectAll: {
            // checkbox v-model勾选后触发的函数
            set(val) {
                console.log(val);
                this.arr.forEach(ele => {
                    ele.checked = val;
                });
            },
            get() {// 获取:全选的checkbox使用every
                return this.arr.every(ele => {
                    return ele.checked
                })
            }
        }
}
</script>
  • 功能设计中用到every,总结some和every的用法:
  1. some宽泛有1个true就true;
  2. every找到一个flase就false;
  • 计算属性可以存在 set/get:
  1. set : v-model="计算属性" , 参数就是用户的输入;
  2. get: v-model="计算属性" , 对元素的输出, [checked或者value属性等];
总结一下computed和methods的不同
  • computed 优先走缓存, 多次渲染时使用 首先从计算一次, 后续从缓存中获取,直到数据改变触发再次执行计算;
  • methods不存在缓存情况,每次调用都会重新计算;