vue 框架想必从事前端开发的同学都使用过,它的双向数据绑定机制能给我们带来很大的方便。今天闲着没事,尝试着实现一下双向数据绑定,接下来给大家分享一下。
方法允许精确添加或修改对象的属性。它的第一个参数
- Object.defineProperty
是要在其上定义属性的对象,第二个参数
- obj
是要定义或修改的属性的名称,第三个参数
- prop
是一个将被定义或修改的属性的描述符。
- descriptor
返回值: 被传递给函数的对象。
来举个例子:
- var o = Object.defineProperty({},
- 'name', {
- value: 1
- });
- console.log(o) // {name: 1}
这是最基本的定义一个对象的方式。对于属性描述符,还有很多其他属性:
数据描述符和存取描述符均具有以下可选键值:
当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,也能够被删除。默认为 false。
- configurable
当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。
- enumerable
数据描述符同时具有以下可选键值:
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
- value
当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。
- writable
存取描述符同时具有以下可选键值:
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
- get
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给属性。默认为 undefined。
- set
这里只说一下
和
- get
: 看一下这个例子:
- set
- var o = Object.defineProperty({},
- 'name', {
- get: function() {
- return this._name_;
- },
- set: function(value) {
- this._name_ = value * 2;
- }
- });
- o.name = 1;
- console.log(o.name); // 2
给属性
定义了一个
- name
和
- get
,为什么使用
- set
而不是
- _name_
呢?因为
- name
是正在被定义的属性,如果在
- name
或者
- get
中使用
- set
无形之中就会发生递归,导致栈溢出。
- name
这个是自己自定义的,你完全可以设置为
- _name_
、
- $name
等等。
- __name__
另外,使用对象的字面量形式也可以设置
与
- get
:
- set
- var o = {
- get name() {
- return this._name_;
- },
- set name(value) {
- this._name_ = value * 2;
- }
- };
- o.name = 1;
- console.log(o.name); // 2
要实现双向数据绑定,肯定要从
与
- get
下手,在
- set
的函数中重新渲染相关的数据,所以一开始应该是这样的:
- set
- varo= {getname(){
- return this._name_;
- },setname(value){
- this._name_ =value;
- this.render('name');
- },
- render: function(pro){
- document.write(this[pro]);
- }
- };
在浏览器控制台修改一下
试试:
- o.name
如何实现表单控件到数据的绑定呢?在
中,表单元素通过
- Vue
绑定一个变量,类型这样:
- v-model
- <input type="text" v-model="name">
其实
的元素是绑定了一个
- v-model
的自定义事件,我们不考虑那么多,就使用原生的
- input
事件来模拟下。
- oninput
- var o = {
- get name() {
- return this._name_;
- },
- set name(value) {
- this._name_ = value;
- console.log(this._name_);
- },
- inputInit: function() {
- var self = this;
- var vModels = document.querySelectorAll('[v-model]');
- for (let i = 0; i < vModels.length; i++) {
- vModels[i].addEventListener('input',
- function() {
- var property = this.getAttribute('v-model');
- var value = this.value;
- self.name = value;
- })
- }
- }
- }.inputInit();
至此一个简单的双向数据绑定就差不多了,我们模仿一下
的 api 格式,再将代码封装一下:
- Vue
html:
- <input type="text" v-model="name">
- <p v-text="name">
- </p>
javascript:
- function Vue(options) {
- var data = options.data || {};
- var dKeys = Object.keys(data);
- var _this = this;
- this.vData = {};
- // 根据data中的变量数量动态的绑定 get 与 set
- for (let i = 0; i < dKeys.length; i++) {
- Object.defineProperty(this.vData, dKeys[i], {
- get: function() {
- return this['__' + dKeys[i] + '__'];
- },
- set: function(value) {
- this['__' + dKeys[i] + '__'] = value;
- _this.render(dKeys[i]); // 重新渲染相关数据
- }
- })
- }
- for (let i in data) { // 初始化时设置一变vData,触发一遍 set
- this.vData[i] = data[i];
- }
- this.inputInit(); // 给表单组件绑定事件监听
- }
- Vue.prototype.render = function(pro) {
- var vModels = document.querySelectorAll('[v-model=' + pro + ']');
- var vText = document.querySelectorAll('[v-text=' + pro + ']');
- for (var i = 0; i < vModels.length; i++) {
- vModels[i].value = this.vData[pro];
- }
- for (var j = 0; j < vText.length; j++) {
- vText[j].innerText = this.vData[pro];
- }
- };
- Vue.prototype.inputInit = function() {
- var self = this;
- var vModels = document.querySelectorAll('[v-model]');
- for (let i = 0; i < vModels.length; i++) {
- vModels[i].addEventListener('input',
- function() {
- var property = this.getAttribute('v-model');
- var value = this.value;
- self.vData[property] = value;
- })
- }
- };
- var vm = new Vue({
- data: {
- name: 1
- }
- })
来源: http://www.cnblogs.com/smartXiang/p/6759282.html