小码哥的IT人生

首页 > JS > vue

Vue 3.0 响应性 深入响应性原理 实例详解

vue 2022-05-07 17:06:26小码哥的IT人生shichen

现在是时候深入了!Vue 最独特的特性之一,是其非侵入性的响应性系统。数据模型是被代理的 JavaScript 对象。而当你修改它们时,视图会进行更新。这让状态管理非常简单直观,不过理解其工作原理同样重要,这样你可以避开一些常见的问题。在这个章节,我们将研究一下 Vue 响应性系统的底层的细节。

在 Vue Mastery 上免费观看关于深入响应性原理的视频。

#什么是响应性

这个术语在程序设计中经常被提及,但这是什么意思呢?响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。人们通常展示的典型例子,是一份 excel 电子表格 (一个非常好的例子)。

点击此处看视频

如果将数字 2 放在第一个单元格中,将数字 3 放在第二个单元格中并要求提供 SUM,则电子表格会将其计算出来给你。不要惊奇,同时,如果你更新第一个数字,SUM 也会自动更新。

JavaScript 通常不是这样工作的——如果我们想用 JavaScript 编写类似的内容:

var val1 = 2
var val2 = 3
var sum = val1 + val2
// sum
// 5
val1 = 3
// sum
// 5

如果我们更新第一个值,sum 不会被修改。

那么我们如何用 JavaScript 实现这一点呢?

  1. 检测其中某一个值是否发生变化
  2. 用跟踪 (track) 函数修改值
  3. 用触发 (trigger) 函数更新为最新的值

#Vue 如何追踪变化?

当把一个普通的 JavaScript 对象作为 data 选项传给应用或组件实例的时候,Vue 会使用带有 getter 和 setter 的处理程序遍历其所有 property 并将其转换为 Proxy。这是 ES6 仅有的特性,但是我们在 Vue 3 版本也使用了 Object.defineProperty 来支持 IE 浏览器。两者具有相同的 Surface API,但是 Proxy 版本更精简,同时提升了性能。

试一试

完整实例:

<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 3.0 响应性 深入响应性原理</title>
<script src="https://unpkg.com/vue@3.0.0/dist/vue.global.js"></script>
<style>
@function strip-unit($value) {
  @return $value / ($value * 0 + 1);
}
@mixin fluid-type($min-vw, $max-vw, $min-font-size, $max-font-size) {
  $u1: unit($min-vw);
  $u2: unit($max-vw);
  $u3: unit($min-font-size);
  $u4: unit($max-font-size);
  @if $u1 == $u2 and $u1 == $u3 and $u1 == $u4 {
    & {
      font-size: $min-font-size;
      @media screen and (min-width: $min-vw) {
        font-size: calc(#{$min-font-size} + #{strip-unit($max-font-size - $min-font-size)} * ((100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)}));
      }
      @media screen and (min-width: $max-vw) {
        font-size: $max-font-size;
      }
    }
  }
}
#app {
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
}
main {
  margin: 0 0 0 20px;
  width: 96%;
  height: 400px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr;
  grid-column-gap: 40px;
}
h2 {
  color: #273849;
  text-align: center;
  margin-top: 40px;
  @include fluid-type(300px, 1200px, 14px, 28px);
}
section {
  padding: 0;
}
* { box-sizing: border-box; }
body {
  font-family: 'Source Sans Pro', sans-serif;
  color: #4f5959;
}
#overlay {
  opacity: 0;
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(255, 255, 255, 0.9);
  z-index: 1000;
}
.replaybutton {
  display: table;
  border: none;
  padding: 0.7rem 1.5rem 0.9rem;
  margin: 100px auto;
  border-radius: 4px;
  text-decoration: none;
  background: rgb(66, 185, 131);
  color: #ffffff;
  font-family: 'Source Sans Pro', sans-serif;
  font-size: 1.2rem;
  cursor: pointer;
  text-align: center;
  transition: background 250ms ease-in-out,
              transform 150ms ease;
  -webkit-appearance: none;
  -moz-appearance: none;
}
.replaybutton:hover,
.replaybutton:focus {
    background: #36996c;
}
.replaybutton:focus {
    outline: 1px solid #fff;
    outline-offset: -4px;
}
button:active {
    transform: scale(0.99);
}
.replayicon {
  margin: 0 0 -4px 2px;
}
$bwidth: 200px;
$bheight: 100px;
.scene {
  width: $bwidth;
  height: $bwidth;
  margin: 15px;
  perspective: 400px;
}
.cube {
  width: $bwidth;
  height: $bwidth;
  position: relative;
  transform-style: preserve-3d;
  transform: translateZ(-$bheight);
  transition: transform 1s ease;
}
.cube.show-front  { transform: translateZ(-$bheight) rotateY(   0deg); }
.cube.show-right  { transform: translateZ(-$bheight) rotateY( -90deg); }
.cube.show-back   { transform: translateZ(-$bheight) rotateY(-180deg); }
.cube.show-left   { transform: translateZ(-$bheight) rotateY(  90deg); }
.cube.show-top    { transform: translateZ(-$bheight) rotateX( -90deg); }
.cube.show-bottom { transform: translateZ(-$bheight) rotateX(  90deg); }
.face {
  font-family: 'Roboto Mono', monospace;
  position: absolute;
  width: $bwidth;
  height: $bwidth;
  border: 2px dotted #4f5959;
  line-height: 200px;
  font-size: 40px;
  font-weight: bold;
  color: rgba(66, 185, 131, 0.68);
  text-align: center;
  background-color: rgba(255, 255, 255, 0.75);
}
.front  { transform: rotateY(  0deg) translateZ($bheight); }
.right  { transform: rotateY( 90deg) translateZ($bheight); }
.back   { transform: rotateY(180deg) translateZ($bheight); }
.left   { transform: rotateY(-90deg) translateZ($bheight); }
.top    { transform: rotateX( 90deg) translateZ($bheight); }
.bottom { transform: rotateX(-90deg) translateZ($bheight); }
label { margin-right: 10px; }
.code, pre, code {
  font-family: 'Roboto Mono', monospace;
  @include fluid-type(500px, 1200px, 9px, 13px);
}
.handler {
  margin-top: 70px;
  padding: 0;
}
.string {
  color: #42b983;
}
.keyword {
  color: #d63200;
}
.sp {
  margin-left: 20px;
}
.explainer {
  height: 50px;
}
.explainer, .code1, .code2, .code3, .cube1, .cube2 {
  visibility: hidden;
}
.visually-hidden {
  position: absolute !important;
  height: 1px;
  width: 1px;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}
</style>
</head>
<body>
<div id="app">
  <div id="overlay">
    <button class="replaybutton">Replay <svg class="replayicon" height="20" width="20" fill="#fff" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
  <path d="m 8.0017778,1037.4886 0,1.7441 c -2.79721,0 -5.23232,1.9407 -5.85352,4.668 -0.6212,2.7274 0.73261,5.5328 3.25391,6.7442 2.5213,1.2113 5.5558192,0.5155 7.2968692,-1.6739 1.74105,-2.1893 1.73629,-5.3045 -0.0117,-7.4883 l -1.17187,0.9375 c 1.31573,1.6438 1.32022,3.9693 0.01,5.6172 -1.31049,1.6479 -3.5768192,2.1677 -5.4746092,1.2559 -1.89779,-0.9118 -2.90703,-3.0057 -2.43945,-5.0586 0.46757,-2.0529 2.28516,-3.502 4.39062,-3.502 l 0,1.7989 2.9999992,-2.5215 z" color="#000" font-weight="400" font-family="sans-serif" overflow="visible" transform="translate(0 -1036.362)"/>
  <style>
  </style>
</svg></button>
  </div>
  <div class="explainer">
    <h2 class="explain1">We start with an object</h2>
    <h2 class="explain2 visually-hidden">We add a handler and proxy the object</h2>
    <h2 class="explain3 visually-hidden">In this case it's the same</h2>
    <h2 class="explain4 visually-hidden">But look! We can intercept the object with this proxy</h2>
    <h2 class="explain6 visually-hidden">But here's the cool part: if we change the first object...</h2>
    <h2 class="explain7 visually-hidden">The proxied object updates accordingly, without adjusting the handler!</h2>
    <h2 class="explain8 visually-hidden">With reactivity we can respond to changes instantly!  

版权所有 © 小码哥的IT人生
Copyright © phpcodeweb All Rights Reserved
ICP备案号:苏ICP备17019232号-2  

苏公网安备 32030202000762号

© 2021-2024