Vue 添加响应式属性

更新日期: 2019-08-07阅读: 3k标签: 响应式

此文使用的 vue 版本是 2.0+,在线例子看这里,下面顺便也把关键代码贴出来。

<template>
  <div class="hello">
    <button @click="inputvalue.aaaa = 'aaaa is here'">show aaaa</button>
    <button @click="$forceUpdate()">forceupdate</button> {{inputvalue.aaaa}}
    <br />
    cccc {{inputvalue.cccc}}
    <input v-model="inputvalue.cccc" placeholder="with v-model" />
    <input
      @input="inputvalue.cccc = $event.target.value"
      :value="inputvalue.cccc"
      placeholder="with @input"
    />
    <br />
    bbbb {{inputvalue.bbbb}}
    <input v-model="inputvalue.bbbb" placeholder="with v-model" />
    <input
      @input="inputvalue.bbbb = $event.target.value"
      :value="inputvalue.bbbb"
      placeholder="with @input"
    />
  </div>
</template>

<script>
  export default {
    data() {
      return {
        inputvalue: {
          bbbb: '',
        },
      }
    },
  }
</script>


提出问题

最近的项目大量接触到动态新增的数据,觉得必须要搞清楚到底什么时候 vue 会让视图更新,视图修改数据又会不会反映到数据模型。

于是写了简单几个例子作为对比,结合一年前研究了一下但是现在忘得差不多的 Vue 原理知识,解决了这么个问题 ——什么情况下动态添加对象属性是安全操作(换句话说就是可以保证数据是响应式的)?


直接赋值为什么不可以

首先解释例子中 inputvalue.aaaa 不显示的问题。这要从 Vue 的响应式原理说起。在初始化的时候 Vue 会把 data 的数据递归扫描一遍,设置 setter 和 getter。

getter 的作用是在数据被读取时记下当前的调用者,这个调用者也就是这个数据的“订阅者”。若视图使用了某个数据,处理页面时就会调用该数据,成为该数据的一个订阅者。

setter 的作用是在数据被赋值时,会提醒他的订阅者该数据已更新,然后订阅者就知道要运行对应的更新操作,例如视图更新、watch 函数。设置 getter,setter 常被称为劫持,感觉也挺形象的,下面就简单用劫持指代这个行为。

既然在初始化时数据才被劫持,那么你突然的定义 this.inputvalue.aaaa = 'aaaa is here' 显然会让 Vue 猝不及防。这个属性即使有订阅者,但是因为没有走到“劫持”这一步,所以这个属性根本意识不到他有订阅者。

其实把数据打印出来可以简单地判定这个数据是否已经被劫持。如下图,bb 没有被劫持,aa、cc 都已被劫持。



应对方法是什么

最简单的方法是:直接在 data 写清楚,也就是页面用了什么属性都必须写上。例如对于 inputvalue.aaaa,就直接在 data 里面加上 aaaa 属性。

但是...想了想,这大概不算“动态”添加了吧。

使用 set

向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = 'hi')

Vue.set 或者 Vue 实例的 $set 都是一样的,总之就是手动触发一次劫持,之后在更新的时候就能触发视图重新渲染啦!不过,其实 set 在一种情况下会失效,这个后面会提到...

使用 forceUpdate

这个方法算是一种曲线救国吧。如果你不需要双向绑定,在动态新增属性时你可以使用 $forceUpdate()。这个函数的作用就如其名,强制更新重新渲染。

上面说过了,虽然你设置新数据没有通知页面重新渲染,不过数据终究是改了。所以你只需要强制更新视图,就能看到数据修改后的效果。

Vue 单向绑定

<input
  :value="myValue.property"
  @input="myValue.property = $event.target.value"
/>

你可能从未听过 Vue 单向绑定,但是这样做也算是一个单向绑定了,当你的输入确实地改变了 myValue.property 的值,但是不会触发任何关于 myValue.property 的更新。真的需要更新的时候 forceUpdate 就可以了。

数组呢

如果数组里有对象,只要单个对象符合上面操作即可,没有特别需要注意的地方。

但是老调重弹,数组更新方法还是需要注意,你可以通过整个数组重新赋值以及 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 这几个经过包裹的方法触发更新。


奇葩情况

例子

对比上面 cccc 的两个输入框:

<input v-model="inputvalue.cccc" placeholder="with v-model" />
<input
  @input="inputvalue.cccc = $event.target.value"
  :value="inputvalue.cccc"
  placeholder="with @input"
/>

进行两种操作:

  1. 先在 with v-model 框输入,后在 with @input 框输入
  2. 先在 with @input 框输入,后在 with v-model 框输入

操作一,一切正常;操作二,无法更新。这就证明坊间流传的 v-model 是 @input 和 :value 的语法糖这个说法至少放在现在肯定是错的(其实我往下试了几个版本,这两个操作表现都是不一致的,觉得很迷惑,但是这不是重点,先不纠结了)。

那么 v-model 到底做了什么

在 stackoverflow 上经过大佬指点,上面的情况其实很容易理解,造成这个区别的重点有两个:

  1. v-model 处理对象属性会自动触发 set -> 相关源码
  2. set 对已存在的属性并不会再次让他变为“响应式” -> 相关源码

所以对于操作一,v-model 帮你把数据 set 了,自然一切正常;操作二,@input 先把属性直接静态添加了,到了 v-model 的时候 set 不会再劫持已经存在的属性。

这就引出了一个需要注意的地方,若是先直接赋值,即使再用 set 也不能再劫持这个属性了,这个可怜弱小又的属性已经无法再变成响应式了。

原文:https://ssshooter.com/2019-09-03-vue-binding/


链接: https://fly63.com/article/detial/5177

移动端web app要使用rem实现自适应布局:font-size的响应式

rem是相对于根元素html,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。

使用现代CSS的响应式版面

通过模块化缩放,使用传统属性和calc()来动态缩放你的字体大小.为字体大小使用百分比.给文本内容和媒体查询使用em,针对不同视口尺寸使用不同缩放值.视口越小,缩放比例越小,使用媒体查询或者media()函数基于视口来改变比例和基础字号

web响应式图片的5种实现

在目前的前端开发中,我们经常需要进行响应式的网站开发。本文着重介绍一下弹性图片,也就是响应式图片的解决方案:js或服务端、srcset 、sizes 、picture标签、svg图片

HTML5+CSS3响应式垂直时间轴,高端,大气

HTML5+CSS3响应式垂直时间轴,使用了HTML5标签<section>,时间轴中所有的内容包括标题、简介、时间和图像都放在.cd-timeline-block的DIV中,多个DIV形成一个序列,并把这些DIV放在<section>中。

实现响应式_CSS变量

CSS 变量是 CSS 引入的一个新特性,目前绝大多数浏览器已经支持了,它可以帮助我们用更少的代码写出同样多的样式,大大提高了工作效率,本篇文章将教你如何使用 CSS 变量(css variable)。CSS中原生的变量定义语法是:--*,变量使用语法是:var(--*),其中*表示变量名称

vue响应式原理及依赖收集

Vue通过设定对象属性的setter/getter方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

vue响应式系统--observe、watcher、dep

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的JavaScript 对象,而当你修改它们时,视图会进行更新,这使得状态管理非常简单直接,我们可以只关注数据本身

Responsive Web Design 响应式网页设计

常见的布局方案:固定布局:以像素作为页面的基本单位,不管设备屏幕及浏览器宽度,只设计一套尺寸;可切换的固定布局:同样以像素作为页面单位,参考主流设备尺寸

响应式布局的实现

响应式布局,即 Responsive design,在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。响应式布局的关键不仅仅在于布局

深入响应式原理

说到响应式原理其实就是双向绑定的实现,说到 双向绑定 其实有两个操作,数据变化修改dom,input等文本框修改值的时候修改数据1. 数据变化 -> 修改dom;2. 通过表单修改value -> 修改数据

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!