RubyLouvre / avalon

an elegant efficient express mvvm framework
http://avalonjs.coding.me/
Other
5.8k stars 1.42k forks source link

component中$watch监听属性,模糊匹配*不能用 #1473

Closed areyouse7en closed 8 years ago

areyouse7en commented 8 years ago

/! built in 2016-6-15:12 version 2.09 by 司徒正美 /

我把之前分页的内容抽出来做了个组件,在更新页码的时候碰到了问题,最后是想通过监听pager的属性(curPage,totalPages,totalItems)然后改变pageItems。 在组件中使用 this.$watch("pager.", function(a, b, name) {}) 的时候,无效。 改成pager.totalPages这种却可以。然后在vm上使用也是可以的。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>avalon test</title>
    <link rel="stylesheet" type="text/css" href="http://cdn.amazeui.org/amazeui/2.7.0/css/amazeui.min.css">
    <script src="avalon.js"></script>
    <script src="pager.js"></script>
    <script>
    var vm = avalon.define({
        $id: "test",
        pager: {
            curPage: 1,
            totalItems: 0,
            totalPages: 0,
        },
        pageSize: 5,
        pageItems: [1],
        getList: function(page) {
            this.pager.curPage = page;
            this.pager.totalPages = 100;
        }
    });

    // vm的*监听是有效的
    vm.$watch('pager.*', function(a, b, name) {
        console.log(name + '发生变化(模糊匹配)');
    });
    </script>
</head>

<body>
    <div class="am-container am-padding" ms-controller="test">
        <ms-pagination ms-widget="{getList:@getList}"></ms-pagination>
    </div>
</body>

</html>

js代码如下:

'use strict';
/**分页组件
 *样式基于amazeui http://cdn.amazeui.org/amazeui/2.7.0/css/amazeui.min.css
 */

// html编译成string
function html2str(fn) {
    return fn.toString().replace(/^[^\/]+\/\*!?\s?/, '').
    replace(/\*\/[^\/]+$/, '').trim().replace(/>\s*</g, '><')
}

var pagetpl = html2str(function() {
    /*
    <div class="am-g">
        <div class="am-u-md-4">
            <p class="am-margin am-text-sm">共 {{@pager.totalItems}} 条记录</p>
        </div>
        <div class="am-u-md-8">
            <ul class="am-pagination am-pagination-right am-text-xs" ms-visible="@pager.totalPages > 0">
                <li ms-class="{'am-disabled' : @pager.curPage == 1}"><a href="javascript:;" ms-click="@getList(1)">首页</a></li>
                <li ms-class="{'am-disabled' : @pager.curPage == 1}"><a href="javascript:;" ms-click="@getList(@pager.curPage-1)"><span class="am-icon-angle-double-left"></span></a></li>
                <li ms-for="el in @pageItems" ms-class="{'am-active' : @pager.curPage == el}">
                    <a href="javascript:;" ms-click="@getList(el)">{{el}}</a>
                </li>
                <li ms-class="{'am-disabled' : @pager.curPage == @pager.totalPages}"><a href="javascript:;" ms-click="@getList(@pager.curPage + 1)"><span class="am-icon-angle-double-right"></span></a></li>
                <li ms-class="{'am-disabled' : @pager.curPage == @pager.totalPages}"><a href="javascript:;" ms-click="@getList(@pager.totalPages)">尾页</a></li>
            </ul>
        </div>
    </div>
    */
});

avalon.component('ms-pagination', {
    template: pagetpl,
    defaults: {
        pager: {
            curPage: 1,
            totalItems: 0,
            totalPages: 0,
        },
        pageSize: 10,
        pageItems: [1],
        getList: function(page) {
            this.pager.curPage = page;
        },
        onInit: function() {
            this.$watch('pager.*', function(a, b, name) {
                console.log(name + '变了');
                if (this.pager.totalPages <= 5) {
                    this.pageItems = avalon.range(1, this.pager.totalPages + 1);
                } else {
                    if (this.pager.curPage < 4) {
                        this.pageItems = avalon.range(1, 6);
                    } else if (this.pager.curPage > 3 && this.pager.curPage < this.pager.totalPages - 1) {
                        this.pageItems = avalon.range(this.pager.curPage - 2, this.pager.curPage + 3);
                    } else {
                        this.pageItems = avalon.range(this.pager.totalPages - 4, this.pager.totalPages + 1);
                    }
                }
            })
        },
        onReady: function() {
            this.getList(1);
        },
        onViewChange: function() {
            console.log('changed');
        }
    }
});
RubyLouvre commented 8 years ago

不要在组件里使用$watch * ,性能会超差

RubyLouvre commented 8 years ago

因为组件VM是一个合成VM,它包含了上面VM的所有属性

areyouse7en commented 8 years ago

噢。。 还有个问题,就这个分页,点几次下一页或者页码的时候,会出现错乱,当前页是5,5和7同时都加上了active,感觉是多次渲染了。。

areyouse7en commented 8 years ago

司徒大大你看下,是不是ms-class或者ms-attr在component里使用的时候,渲染会出现延迟或者错误。我截个图给你看。

ms-class-in-ms-component-1

ms-class-in-ms-component ms-class-in-ms-component-2

<li ms-for="el in @pageItems" ms-class="{'am-active' : @pager.curPage==el}">
                    <a href="javascript:;" ms-click="@getList(el)">{{@pager.curPage}}-{{el}}:{{@pager.curPage==el}}</a>
                </li>

这个情况在不使用组件,直接for出来的时候是没有的。 真是麻烦你了,分页这个组件很重要。。我卡了很久了。。

RubyLouvre commented 8 years ago

是的,我也正在处理,应该是版本比较错误了

areyouse7en commented 8 years ago

辛苦啦~~ 提个建议,在onViewChange事件的返回对象中,能否提供change的是哪个属性,就像$watch一样,可以得到old,new,name。 这样我就可以根据需要对某项属性的改变做相应的操作,其他的改变就不操作。

areyouse7en commented 8 years ago

噢,不对。。这个貌似只监听view的变化,属性怎么变都是不会触发的。。

 if (preHTML !== curHTML) {
   cur.vmodel.$fire('onViewChange', {
    type: 'viewchange',
    target: dom,
    wid: wid,
    vmodel: vnode.vmodel
  })
}

那希望可以有一个onAttrChange之类的监听~