Function attempt of Knockout component

Components need to be reused to make sense, so component HTML templates should be independent of external files. The following are component HTML templates

<!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:'within - ' + 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
    /**
     * How to use external templates:
     * 1.Packaging html templates with webpack
     * 2.Load the template file through require.js + text.js
     * 3.Convert the html template to js string and reference the js file with the following code
     */

    /**
     * Description of this component
     * Input format {list:[{name:'',selected:0}],outerIndex}
     * The parent component is required to provide $root.methods.remove/selected
     */
    var template = document.getElementById('template').outerHTML.replace(/\'/ig,'\\\'').replace(/\s*\n\s*/ig,'')
</script>
</body>
</html>

The component HTML template also needs to be imported into other files. The method used here may be low, which is to transfer the component HTML to JS string and import other files into JS file, but it is feasible

// 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:\'within - \' + 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>'

Finally, the ViewModel and business logic are written in the file using the component

<!DOCTYPE html>
<html>

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

<body>
<div>
    ko assembly
</div>
<br>

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

<div data-bind="foreach:{data:outerList(),as:'ol'}">
    <div data-bind="text:'External iteration' + 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>
    /**
     * Reference: http://www.cnblogs.com/smallprogram/p/5976954.html
     *
     * 1.How parent-child components communicate
     * The data of the child component is input through the parent component, so when the child component needs to respond to the user's operation, it should also update the data of the parent component and then notify the child component to update
     *
     * 2.Subcomponent context
     * $root $parent $element etc.
     * Estimate is the context of the parent component
     */
    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: 'External name',
    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
            // It can communicate, although there are some problems in the realization of specific functions
            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>

Tags: Javascript Webpack

Posted on Thu, 02 Apr 2020 14:38:10 -0700 by bran