Object.defineProperty实现双向绑定原理

什么是双向绑定?

1.当一个对象(或变量)的属性改变,那么调用这个属性的地方显示也应该改变,模型到视图(model => view)

2.当调用属性的这个地方改变了这个属性(通常是一个表单元素),那么这个对象(或变量)的属性也会改为最新的值 ,即视图到模型(view => model)

我们怎么知道对象的属性变了?

上文说到,Object.defineProperty 设置对象属性的描述字段里面有两个属性 set (设置属性时被调用)和get(获取属性时被调用),只说不练,你再讲什么?眼见为实好吗?OK ,上代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var user = {};

var defaultName = "狂奔的蜗牛";

Object.defineProperty(user,"name",{

  get:function(){

    console.log("你是不是来获取值啦");

    return defaultName;

  },

  set:function(value){

    console.log("你是不是来设置值啦");

    defaultName = value;

  }

})

console.log(user.name);

user.name = "狂奔的萝卜";

console.log(user.name);

get和set存取时被调用

如上图所示 每当我获取user.name属性时,get方法被调用,get 方法对应的函数被执行,输出 你是不是来获取值啦;每当我设置user.name属性时,set方法对应的函数被执行,输出 你是不是来设置值啦 ; 是的,我们监控到了代码对user.name属性的存取。

说明 假设id="model" 的元素的 value 是user.name的值,既然我们可以在改变属性的执行日志输出(console.log("你是不是来设置值啦");),那么,我们在设置值的时候给id="model" 的元素设置下新值,不就实现了从模型到视图?!!,说干就干

模型到视图(model => view)的同步

说明 假设id="model" 的元素的 value 是user.name的值,既然我们可以在改变属性的执行日志输出(console.log("你是不是来设置值啦");),那么,我们在设置值的时候给id="model" 的元素设置下新值,不就实现了从模型到视图?!!,说干就干

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

<body>

  手写一个简单双向绑定<br/>

  <input type="text" id="model"><br/>

  <div id="modelText"></div>

</body>

<script>

var user = {};

var defaultName = "狂奔的蜗牛";

document.querySelector("#model").value = defaultName;

document.querySelector("#modelText").textContent = defaultName;

//定义属性 监控改变

Object.defineProperty(user,"name",{

  get:function(){

    console.log("你是不是来获取值啦");

    return defaultName;

  },

  set:function(newValue){

    console.log("设置新值");

    defaultName = newValue;

    console.log("实现 模型 => 视图");

    document.querySelector("#model").value = newValue;

    document.querySelector("#modelText").textContent = newValue;

  }

})

console.log("2s 后改变值");

setTimeout(() => {

  //改变值

  user.name = "狂奔的萝卜";

}, 2000);

</script>

模型到视图(model => view)的同步

视图到模型(view => model)的同步

问: 我们能捕捉到view对值更改吗?

答:可以!! id="model" 的input元素的 value 是user.name的值,填充在这个文本框里面,文本框有个“ keyup” 事件,当我们在文本框中输入文字的时候,文本框的值会跟着改变,并且会连续触发keyup事件,那么我们只需要监听这个事件,是不是就可以捕捉到view对值的更改了??既然文本框的值会跟着改变,我们获取最新的值再把新值更新到user.name属性,不就实现了视图到模型(view => model)的同步?没代码说个啥

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

<body>

  手写一个简单双向绑定<br/>

  <input type="text" id="model"><br/>

  <div id="modelText"></div>

</body>

<script>

  var user = {};

  var defaultName = "狂奔的蜗牛";

  var model = document.querySelector("#model");

  var modelText = document.querySelector("#modelText");

  model.value = defaultName;

  modelText.textContent = defaultName;

  //定义属性 监控改变

  Object.defineProperty(user,"name",{

    get:function(){

      console.log("你是不是来获取值啦");

      return defaultName;

    },

    set:function(newValue){

      console.log("设置新值");

      defaultName = newValue;

      model.value = newValue;

      modelText.textContent = newValue;

    }

  })

  model.addEventListener("keyup", function () {

    user.name = this.value;

    console.log("实现 视图 => 模型");

  }, false)

</script>

view2model.gif

【最终源码】

在上述代码的基础上,加入了 用户输入中文的判断(用户输入中文时,频繁触发 keyup事件,但实际上输入并没有结束。)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

<!DOCTYPE html>

<html>

<head>

  <meta charset="utf-8">

  <title>双向绑定</title>

</head>

<body>

  手写一个简单双向绑定<br/>

  <input type="text" id="model"><br/>

  <div id="modelText"></div>

</body>

<script>

  var model = document.querySelector("#model");

  var modelText = document.querySelector("#modelText");

  var defaultName = "defaultName";

  var userInfo = {}

  model.value = defaultName;

  Object.defineProperty(userInfo, "name", {

    get: function () {

      return defaultName;

    },

    set: function (value) {

      defaultName = value;

      model.value = value;

      console.log("-----value");

      console.log(value);

      modelText.textContent = value;

    }

  })

  userInfo.name = "new value";

  var isEnd = true;

  model.addEventListener("keyup", function () {

    if (isEnd) {

      userInfo.name = this.value;

    }

  }, false)

  //加入监听中文输入事件

  model.addEventListener("compositionstart", function () {

    console.log("开始输入中文");

    isEnd = false;

  })

  model.addEventListener("compositionend", function () {

    isEnd = true;

    console.log("结束输入中文");

  })

</script>

</html>

【完结】

Object.defineProperty 可以做很多好玩儿的,自己慢慢探索哈~

猜你喜欢

转载自blog.csdn.net/A13330069275/article/details/83412279
今日推荐