Skip to content
This repository has been archived by the owner on Dec 12, 2017. It is now read-only.

请教一个问题 #23

Open
njleonzhang opened this issue Dec 9, 2016 · 24 comments
Open

请教一个问题 #23

njleonzhang opened this issue Dec 9, 2016 · 24 comments
Labels

Comments

@njleonzhang
Copy link
Contributor

我也在做一个三级联动的组件,遇到一个问题。就是给3级联动组件根据给定值进行初始化的问题。

比如你这个省市区三级联动,如果我给省市区3个值分别一个值对其进行初始化。那么这3个值会传入组件并先后赋给3个select,假设我先给省赋值,再给市复制,再给区复制,那么问题就来了,给省复制给触发联动的逻辑,省改变会取清空市和区的值。。。。。

所以您是如何解决这个问题的呢?看了代码,没整明白

@QingWei-Li
Copy link
Owner

我的那个实现也是给「省」赋值就会触发「市」、「区」改变呀 😂,按照你的说法先给省赋值,再给市赋值,为啥会清空。。。

@njleonzhang
Copy link
Contributor Author

njleonzhang commented Dec 14, 2016

我的实现里用了watch。但是watch会延迟执行。

伪代码大概是这样的:

props:{
  id:String
}

watch: {
    id() {
        initWithValue()
    },
    ops1Selected() {
       this.ops2Selected = ''
       this.ops3Selected = ''
    }
    .......
}


initWithValue() {
HttpService.SCPrefixGet(`selector/room/${this.id}/selects`).then(data => {
              this.ops1 = data.ops1
              this.ops2 = data.ops2
              this.ops3 = data.ops3
               
              this.ops1Selected = data.ops1Selected
              this.ops2Selected = data.ops2Selected
              this.ops3Selected = data.ops3Selected
            })
}

但是我每次初始化完之后,我都发现ops2和ops3并没有选择,只有ops1是选择了的。
仔细调了一下发现这些复制先执行了。

              this.ops1Selected = data.ops1Selected
              this.ops2Selected = data.ops2Selected
              this.ops3Selected = data.ops3Selected

但是ops1Selected的watch后面又执行了一次,把所有的值都清空了。导致了这样的问题。watch貌似是异步的所以导致这样的问题。。。

@QingWei-Li
Copy link
Owner

是的,watch 没法保证执行顺序,用 computed 好一些

@njleonzhang
Copy link
Contributor Author

njleonzhang commented Dec 14, 2016

@QingWei-Li computed能保证同步执行么?但是我的逻辑都是ajax请求,不太好用computed去实现。每次选择options都有可能是去后台拿的。这样options就无法用computed了。

我之前看了一点vue2.0的源码,comupted和watch的实现其实是一套。都是一个Watcher类,现在这些细节想不太起来了。我这种情况应该怎么处理比较好呢?

@QingWei-Li
Copy link
Owner

不一样吧。。computed 是 getter setter,同步执行的;watch 应该是一个 Watcher。

@QingWei-Li
Copy link
Owner

那你可以动态初始化 watch 呗,获取数据后再执行 this.$watch(xxx)

@njleonzhang
Copy link
Contributor Author

njleonzhang commented Dec 14, 2016

@QingWei-Li 好吧 我现在就这么干的,好恶心,数据每次变化,解watch,然后加watch,简直恶心。

@QingWei-Li
Copy link
Owner

我得空研究下

@njleonzhang
Copy link
Contributor Author

@QingWei-Li 感谢

@njleonzhang
Copy link
Contributor Author

仔细看了一下您的代码,感觉上也有这个问题,您的数据更新逻辑是这样的:
province,city,district都是一样的。

如果外部数据变化 ---->
this.province(watch)变化 ----> 
this.current.province变化  ----> 
this.provinceSelected(computed)变化

这样数据就会得到更新,province,city,district会一次走这个逻辑,但是其实每个更新链后面还有逻辑:

如果外部数据变化 ---->
this.province(watch)变化 ----> 
this.current.province变化  ----> 
this.provinceSelected(computed)变化 --->
----------------------------------------------------
change事件触发 ----->  this.citySelected = ''   this.districtSelected = '' 

所以vue在跑这些代码时,必须保证province,city,district的这3条更新链是一次执行的。但是这里混着watch和事件(都是异步的),感觉很难保证这样的顺序。

还有就是当外部数据不按province,city,district的顺序更新数据时,应该也不对。比如按district,city,province更新, 区域更新链先触发,city再触发,省的最后触发,那么前面2个的更新就应该失效了,会被province的change事件触发的this.citySelected = ''和this.districtSelected = '' 给覆盖掉。

  watch: {
    province () {
      this.current.province = ''
    },
    city () {
      this.current.city = ''
    },
    district () {
      this.current.district = ''
    }
  }

不知道我理解的是否正确

@QingWei-Li
Copy link
Owner

我的做法就是同步的,因为数据就是确定的,没考虑过异步的情况。

@njleonzhang
Copy link
Contributor Author

@QingWei-Li 你细看一下我写的东西,我说的是你这个插件的逻辑。

@QingWei-Li
Copy link
Owner

没考虑那么多 😂 不过测试下来没遇到你说的更新顺序导致的问题。。。

@njleonzhang
Copy link
Contributor Author

。。。。晕倒了啊,难道我分析的不对么

@QingWei-Li
Copy link
Owner

不清楚 我周末看看 😂😂

@njleonzhang
Copy link
Contributor Author

@QingWei-Li 我自己搞明白了 。。。。哈哈,发现你的代码有lint错误,顺手改了下 提了个PR。

#24

@njleonzhang
Copy link
Contributor Author

发现另一个问题,有初始值的seletor
image

不管如何选择省市区
image

只要把省选回初始值(广东省),市和区也会变成初始值。(常理来说市和区应该清空才对)
image

这是由实现决定的, 不知道算不算bug。

      get () {
        return this._selected(this.provinceSelected[0], this.current.city || this.city)
      },

我尝试改成清空市和区,但是臣妾做不到。。。。大神可以指点下么。

@QingWei-Li
Copy link
Owner

对,当初想要的就是变成初始值 😂,否则直接置空就好了

@njleonzhang
Copy link
Contributor Author

@QingWei-Li 好像置不了空的,这种场景下this.current.city置空,this.city就会生效。你如何置空呢?

@QingWei-Li
Copy link
Owner

我的意思是当初想要的效果就是返回第一个值,你可以直接改 get() 的返回值

@njleonzhang
Copy link
Contributor Author

njleonzhang commented Dec 22, 2016

我明白你的意思。
但是这个get的技巧性太强了,我不知道该怎么改。。。。

    citySelected: {
      get () {
        return this._selected(this.provinceSelected[0], this.current.city || this.city)
      },

     set (value) {
          this.current.city = value
     }
   }
  1. 首先current的值在citySelected改变的时候被赋值,然后通过get反作用于citySelected。所以在city被选择的时候current相当于一个赋值的跳板。。。get能返回this.current.city

  2. 而this.city是prop,始终和组件外部传入的值保持一致。当city变化时(组件外部赋值),current值被清空。这样就让this.city生效。get能返回this.city

  3. 而当provice选择变化的时候,current值也清空了,此时this.city生效。但是由于provinceSelected的变化,this._selected查询用的又是id,所以此时get又能正确返回出空值。

  4. 但是当provice选择会初始值时,city的get就会返回成city的初始值。

现在如果想让第4中情况时,返回空值不知道怎么改哎。。。。感觉这是一个数学问题。这个get就是一个公式。。。

你可以直接改 get() 的返回值

咋改呢?

@njleonzhang
Copy link
Contributor Author

@QingWei-Li 有空的话 能帮忙解释下么。。。哈哈

@QingWei-Li
Copy link
Owner

....忘了 如果按这种写法 似乎就没法改。之前写代码太 💩 了

@njleonzhang
Copy link
Contributor Author

@QingWei-Li :( 僵硬,这已经是我找到的最好的实现了。

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants