您当前的位置: 首页 > 

【03】

暂无认证

  • 2浏览

    0关注

    196博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

优雅的给vue对象设置初始值

【03】 发布时间:2021-02-22 15:03:41 ,浏览量:2

vue 中经常定义很多data ,在用户进行一些操作后,需要将data中的某个对象定义为初始值,最常见的为表单数据

初始化指定对象
form: {
	title: '',
	desc: '',
	url: ''
}

大众都会选择以下方法进行初始化值

this.form = {
	title: '',
	desc: '',
	url: ''
}

其实还可以这样

// Object.assign(this.form, this.$options.data().form)
this.form = this.$options.data().form
示例代码

  
    setData
    
      title:
      
    
    
      desc:
      
    
    
      url:
      
    
    
      初始化方法1
      初始化方法2
    
  


export default {
  name: 't3',
  data() {
    return {
      form: {
        title: '',
        desc: '',
        url: ''
      }
    }
  },
  methods: {
    setData(){
      this.form = {
        title: '零三的笔记',
        desc: 'web03',
        url: 'web03.cn'
      }
    },
    initFn1(){
      this.form = {
        title: '',
        desc: '',
        url: ''
      }
    },
    initFn2(){
      //Object.assign(this.form, this.$options.data().form)
	  this.form = this.$options.data().form
    }
  }
}


div{
  padding: 5px 20px;
}

初始化整个data

对于初始化整个data,如果还是一个一个data属性进行赋值,那这难免太low了,可以直接使用Object.assign进行初始化整个data

关键代码

Object.assign(this.$data, this.$options.data())

示例


  
    setData
    
      title:
      
    
    
      desc:
      
    
    
      url:
      
    
    
      msg: {{otherData.msg}}
    
    
      初始化data
    
  


export default {
  name: 't3',
  data() {
    return {
      form: {
        title: '',
        desc: '',
        url: ''
      },
      otherData: {
        msg: ''
      }
    }
  },
  methods: {
    setData(){
      this.form = {
        title: '零三的笔记',
        desc: 'web03',
        url: 'web03.cn'
      }
      this.otherData.msg = 'msg data'
    },
    initFn(){
      Object.assign(this.$data, this.$options.data())
    }
  }
}


div{
  padding: 5px 20px;
}

同样支持初始化form新增的属性

Objeact.assign初始化form的弊端

个人发现Objeact.assign在原data数据进行增删新属性之后,会出现数据遗留现象,以下案例


  
    setData
    
      title:
      
    
    
      desc:
      
    
    
      url:
      
    
    
      attr:{{form.attr}}
    
    
      set attribute
      初始化data
    
  


export default {
  name: 't3',
  data() {
    return {
      form: {
        title: '',
        desc: '',
        url: ''
      },
      otherData: {
        msg: ''
      }
    }
  },
  methods: {
    setData(){
      this.form = {
        title: '零三的笔记',
        desc: 'web03',
        url: 'web03.cn'
      }
      this.otherData.msg = "msg data"
    },
    setAttribute(){
      //this.form.attr = "我是动态的属性"
      // 或者
      this.$set(this.form, 'attr', "我是动态的属性")
    },
    initFn(){
      Object.assign(this.form, this.$options.data().form)
    }
  }
}


div{
  padding: 5px 20px;
}

以上demo出现了attr遗留的问题,而我们并不希望让他存在

进行优化

- Object.assign(this.form, this.$options.data().form)
+ this.form = this.$options.data().form

Object.assign(this. d a t a , t h i s . data, this. data,this.options.data())支持初始化form新增的属性,且不支持this. d a t a = t h i s . data=this. data=this.options.data()

Objeact.assign初始化整个data弊端

发现在子组件使用Object.assign(this. d a t a , t h i s . data, this. data,this.options.data()),会将props的值清空,查看以下案例 // t3.vue


  
    
  


import child from './child'
export default {
  name: 't3',
  components: {
    child
  },
  data(){
    return {
      parentDataObj: {
        name: '零三'
      },
      parentDataStr: '我是零三'
    }
  }
}

// child.vue


  
    setData
    
      title:
      
    
    
      desc:
      
    
    
      url:
      
    
    
      myDataStr: {{myDataStr}}
    
    
      myDataObj.name: {{myDataObj.name}}
    
    
      初始化data
    
  


export default {
  name: 'child',
  props: ['parentDataStr', 'parentDataObj'],
  data() {
    return {
      form: {
        title: '',
        desc: '',
        url: ''
      },
      myDataStr: this.parentDataStr,
      myDataObj: this.parentDataObj
    }
  },
  methods: {
    setData() {
      this.form = {
        title: '零三的笔记',
        desc: 'web03',
        url: 'web03.cn'
      }
    },
    initFn() {
      Object.assign(this.$data, this.$options.data())
    }
  }
}


div {
  padding: 5px 20px;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaNlHfpf-1613983980768)(https://yuan30-1304488464.cos.ap-guangzhou.myqcloud.com/blog/images/63eb4c91d4aa4323b664348a194ec577.gif)]

解决

- Object.assign(this.$data, this.$options.data())
+ Object.assign(this.$data, this.$options.data.call(this))

分析问题原因

分析Vue实例的初始化逻辑源码, new Vue的时候传了一个对象,把该对象记为options,Vue将options中自定义的属性和Vue构造函数中定义的属性合并为vm. o p t i o n s , v m . options,vm. options,vm.options.data()中的this指向vm. o p t i o n s , 而 m y D a t a S t r 和 B 并 没 有 直 接 挂 在 v m . options,而myDataStr和B并没有直接挂在vm. options,而myDataStr和B并没有直接挂在vm.options下,所以this.myDataStr和this.myDataObj为undefined。

initMixin (Vue: Class) {
    const vm: Component = this
    // ...
    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
    )
    // ...
}

将vm.$options.data映射到vm._data,使得可以通过vm._data访问数据,在映射过程中,通过call将data()的this指向当前的实例vm,并将data()的执行结果返回,因为prop和methods的初始化在data之前,所以这时vm上已有_props和_methods,可以拿到this.myDataObj和this.myDataStr。

initState (vm: Component) {
    // ...
    const opts = vm.$options
    if (opts.props) initProps(vm, opts.props)
    if (opts.methods) initMethods(vm, opts.methods)
    if (opts.data) {
        initData(vm) // 里面通过getData(data, vm)改变this
    }
    // ...
}
  
getData (data: Function, vm: Component): any {
    // ...
    try {
        return data.call(vm, vm) // this替换为vm
    }
    // ...
}

上面把属性映射到了vm._data里,可以通过vm._data.A访问数据,Vue再通过一个代理方法使得vm.A可以直接访问A


proxy(vm, `_data`, key);
  
proxy (target: Object, sourceKey: string, key: string) {
    sharedPropertyDefinition.proxyget = function proxyGetter () {
        return this[sourceKey][key]
    }
    sharedPropertyDefinition.set = function proxySetter (val) {
        this[sourceKey][key] = val
    }
    Object.defineProperty(target, key, sharedPropertyDefinition)
}
总结
  • 初始化没有动态属性的对象,可采用 Object.assign(this.form, this.$options.data().form)

  • 初始化有动态属性的对象一定要使用this.form = this.$options.data().form 【推荐】

  • 初始化data,data()中没有用this来访问props或methods,可不绑定this,使用Object.assign(this. d a t a , t h i s . data, this. data,this.options.data())

  • 初始化data,data()中若用了this来访问props或methods,一定要绑定this,使用Object.assign(this. d a t a , t h i s . data, this. data,this.options.data.call(this)) 【推荐】

关注
打赏
1657344724
查看更多评论
立即登录/注册

微信扫码登录

0.0393s