Knockout 组件功能尝试

组件需要被复用才会有意义,所以组件HTML模板应当独立在外部文件中,以下是组件HTML模板

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="template" data-bind="attr:{'data-outer-index':outerIndex()}">
    <!-- ko foreach:{data:list(),as:'o'} -->
    <div>
        <span data-bind="text:'内 - ' + o.name()"></span>&nbsp;
        <span data-bind="click:$root.methods.remove.bind($parent.outerIndex(),$index())">remove</span>&nbsp;
        <span data-bind="click:$root.methods.selected,text:o.selected() == 0?'selected':'done'">selected</span>&nbsp;
    </div>
    <!-- /ko -->
</div>
<script>
    // see components.js
    /**
     * 使用外部模板的方法:
     * 1.通过webpack打包html模板
     * 2.通过require.js + text.js加载模板文件
     * 3.通过以下代码将html模板转换js字符串并引用js文件
     */

    /**
     * 本组件说明
     * 输入格式{list:[{name:'',selected:0}],outerIndex}
     * 需要父组件提供$root.methods.remove/selected
     */
    var template = document.getElementById('template').outerHTML.replace(/\'/ig,'\\\'').replace(/\s*\n\s*/ig,'')
</script>
</body>
</html>

组件HTML模板还需要导入到其他文件内部,此处使用的方法可能比较low,就是将组件HTML转JS字符串,其他文件导入JS文件的方式,但是是可行的

// see components.html
var COMP_MY_COMPONENT_HTML = '<div id="template" data-bind="attr:{\'data-outer-index\':outerIndex()}"><!-- ko foreach:{data:list(),as:\'o\'} --><div><span data-bind="text:\'内 - \' + o.name()"></span>&nbsp;<span data-bind="click:$root.methods.remove.bind($parent.outerIndex(),$index())">remove</span>&nbsp;<span data-bind="click:$root.methods.selected,text:o.selected() == 0?\'selected\':\'done\'">selected</span>&nbsp;</div><!-- /ko --></div>'

最后在使用该组件的文件中编写ViewModel以及业务逻辑

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>ko组件</title>
</head>

<body>
<div>
    ko组件
</div>
<br>

<div data-bind="text:outerName"></div>
<br>

<div data-bind="foreach:{data:outerList(),as:'ol'}">
    <div data-bind="text:'外部迭代' + ol"></div>
    <div data-bind="component:{name:'my-component',params:{outerIndex:$index(),list:ol}}"></div>
    <br>
</div>
<script type="text/javascript" src="knockout-3.4.2.js"></script>
<script type="text/javascript" src="knockout.mapping.min.js"></script>
<script type="text/javascript" src="components.js"></script>
<script>
    /**
     * 参考:http://www.cnblogs.com/smallprogram/p/5976954.html
     *
     * 1.父子组件如何通信
     * 子组件的数据是通过父组件输入的,因此子组件需要响应用户操作时,也应当通过更新父组件数据后,再通知子组件更新
     *
     * 2.子组件上下文
     * $root $parent $element等
     * 估计就是父组件的上下文
     */
    ko.components.register('my-component', {
        viewModel: {
            createViewModel: function(p, c) {
                function SubViewModel(p){
                    var self = this
                    var pJS = ko.mapping.toJS(p)
                    self.outerIndex = ko.observable(p.outerIndex)
                    self.list = ko.observableArray(p.list)
                }
                return new SubViewModel(p)
            }
        },

        template: COMP_MY_COMPONENT_HTML
    })

var outerData = {
    outerName: '外部名称',
    outerList: [
        [{
            name: 'a',
            selected: 0
        }, {
            name: 'b',
            selected: 0
        }, {
            name: 'c',
            selected: 0
        }],
        [{
            name: 'd',
            selected: 0
        }, {
            name: 'e',
            selected: 0
        }]
    ]
}
var OuterVm = function () {
    var self = this
    self.methods = {
        remove: function(innerIndex) {
            console.log(this)
            console.log(arguments)
            return
            // 是可以通信的,虽然具体功能实现还有点问题
            var outerIndex = this
            var outerList = ko.mapping.toJS(self.outerList)
            if (innerIndex != -1){
                outerList[innerIndex].splice(innerIndex,1)
                ko.mapping.fromJS({outerList:outerList},{},self)
            } else {
                console.log('not found target')
            }
        },
        selected: function(){
            console.log(this)
            console.log(arguments)
            arguments[0].selected(1)
        }
    }
}
var outerVm = new OuterVm()
ko.mapping.fromJS(outerData, {}, outerVm)
ko.applyBindings(outerVm, document.body)
</script>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/just_fight_/article/details/80027061