{"id":20022225,"url":"https://github.com/lucifier129/jplus","last_synced_at":"2025-05-05T01:31:23.274Z","repository":{"id":58242372,"uuid":"24182181","full_name":"Lucifier129/jplus","owner":"Lucifier129","description":"jQuery指令插件","archived":false,"fork":false,"pushed_at":"2015-04-28T07:23:47.000Z","size":3414,"stargazers_count":13,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-08T14:52:28.470Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://lucifier129.github.io/jplus/m/index.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lucifier129.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-18T09:28:54.000Z","updated_at":"2019-08-13T15:50:58.000Z","dependencies_parsed_at":"2022-08-31T04:22:14.695Z","dependency_job_id":null,"html_url":"https://github.com/Lucifier129/jplus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lucifier129%2Fjplus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lucifier129%2Fjplus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lucifier129%2Fjplus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lucifier129%2Fjplus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lucifier129","download_url":"https://codeload.github.com/Lucifier129/jplus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252423124,"owners_count":21745547,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T08:39:36.671Z","updated_at":"2025-05-05T01:31:18.267Z","avatar_url":"https://github.com/Lucifier129.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jplus\n\n`jQuery指令插件`\n\n\n[在线教程与案例]\n\n\n## 介绍\n\n### 引用`jplus`\n\n作为`jQuery插件`引入\n\n```html\n\u003cscript type=\"text/javascript\" src=\"jquery.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"jplus.js\"\u003e\u003c/script\u003e\n```\n\n### 将数据同步到视图\n\n首先：在`html`中使用`data-bind`属性，按照`css语法`书写`key:value;`\n    \n```html\n\u003cdiv id=\"scope\"\u003e\n    \u003cp data-bind=\"attr-class:className\"\u003eHello \u003cspan data-bind=\"text:name\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n然后：在`javascript`中调用`jQuery`的`refresh`方法\n\n```javascript\n$('#scope').refresh({\n    name: 'jplus.js',\n    className: 'descri'\n})\n```\n\n大功告成\n\n`html` 标签的`data-bind`属性中，`key`可以为如下内容\n\n* `jQuery`实例的方法，即在实例化后，手动添加在该实例上的方法名\n* `jQuery`的原型方法的名字，即`$.fn`上的方法名\n* `jQuery`实例对应的`dom`元素的方法名与属性名\n\n而`value`则对应数据对象的属性名。\n\n`key`和`value`都支持点操作符和方括号操作符链式取值, 如下都是合法的\n* `a.b.c.e.f`\n* `a[0].b[1]`\n\n注意事项：避免空指令。如果找不到对应的方法函数，数据将直接成为`dom元素`的属性\n\n\n### 将`jplus`用作模板引擎\n\n只要将数据打包成数组，`jplus`就会自动安排同等数量的元素对应；不够的`clone`出来，多余的`remove`掉\n\n```html\n\u003cdiv id=\"scope\"\u003e\n    \u003cul\u003e\n        \u003cli data-bind=\"text:list\"\u003e写一些默认内容，待会儿就被覆盖\u003c/li\u003e\n    \u003c/ul\u003e\n\u003c/div\u003e\n```\n\n```javascript\nvar list = []\n\nfor (var i = 0; i \u003c 20; i += 1) {\n    list[i] = '列表项目' + i\n}\n\nsetInterval(function() {\n    //随机长度\n    var randomLen = Math.floor(Math.random() * list.length + 1)\n    var curList = list.concat().sort(function() {\n        //随机化排序\n        return Math.random() - 0.5\n    })\n    \n    curList.length = randomLen\n    \n    $('#scope').refresh({\n        list: curList\n    })\n}, 800);\n```\n\n注意事项：\n- 只有数据类型一致的数组，才作为模板数据\n- 数据类型不同的数组，全部作为参数传入指令方法\n- 传入空数组，对应的`dom元素`将全部删除\n- 每次调用`refresh`方法，都会即时扫描视图，如果元素被删除，则无法收集指令\n- 可以通过故意为数组追加`null`、`false`等强行将数据类型不一致化，达到传多个参数的目的\n\n## 渲染嵌套数据到视图\n\n将`refresh`作为指令，即可渲染嵌套数据\n\n```html\n\u003cdiv id=\"scope\"\u003e\n    \u003cul\u003e\n        \u003cli data-bind=\"refresh:classList\"\u003e\n            \u003ch3 data-bind=\"text:classTitle\"\u003e\u003c/h3\u003e\n            \u003cul\u003e\n                \u003cli data-bind=\"text:content\"\u003e\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/li\u003e\n    \u003c/ul\u003e\n\u003c/div\u003e\n```\n\n```javascript\nvar data = {\n    classList:[{\n        classTitle:'类名1',\n        content:[1, 2, 3, 4, 5]\n    },{\n        classTitle:'类名2',\n        content:[6, 7, 8, 9, 10]\n    },{\n        classTitle:'类名3',\n        content:[11, 12, 13, 14, 15]\n    },{\n        classTitle:'类名4',\n        content:[16, 17, 18, 19, 20]\n    },{\n        classTitle:'类名5',\n        content:[21, 22, 23, 24, 25]\n    }]\n}\n\n$('#scope').refresh(data)\n```\n\n### 禁止父元素扫描自身的子元素\n\n添加`noscan`属性后，只有该元素的`jQuery实例`调用`refresh`才能刷新视图\n\n```html\n/*添加noscan属性，视图私有化*/\n\u003cdiv noscan\u003e\n\t\u003cspan data-bind=\"text:text\"\u003e\u003c/span\u003e\n\u003c/div\u003e\n```\n\n### 禁止数组数据改变元素数量\n\n添加`norepeat`属性后，遇到数据类型一致的数组，数据比元素多时，忽略多余数据；元素比数据多时，忽略多余元素\n\n```html\n/*不论多少数据，都只更新现有的元素*/\n\u003cdiv norepeat\u003e\n\t\u003cli data-bind=\"text:text\"\u003e\u003c/li\u003e\n\u003c/div\u003e\n```\n\n### 从视图中获取数据\n\n`jQuery`的`API设计`理念之一是：既是`getter`，也是`setter`\n\n```javascript\n$('body').html() // get HTML\n$('body').html(content) // set HTML\n$('body').attr('id') // get ID\n$('body').attr('id', newID) // set ID\n```\n\n对于这类指令。当需要刷新视图时，`jplus`传入数据；当需要从视图中获取数据时，`jplus`不传参数或者只传必要的参数。\n\n在上一个例子中，只需要调用`collect`方法，就从视图中获取了所需的数据。\n\n### 自定义指令\n\n所谓指令，在`jplus`中指写在`html`的`data-bind`属性中，格式类似`css语法`的`键值对`\n\n```html\n\u003cul id=\"scope\"\u003e\n    \u003cli data-bind=\"text:msg; setTitle:title; setData-directive:directive\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n```javascript\n//插件写法，为原型添加方法，属于全局指令\n$.fn.setTitle = function(title) {\n    if (typeof title === 'undefined') {\n        return this.attr('title')\n    } else {\n        this.attr('title', title)\n    }\n}\n\nvar $scope = $('#scope')\n\n//实例特有方法，属于局域指令\n$scope.setData = function(name, val) {\n    if (!name) {\n        return\n    }\n    if (typeof val === 'undefined') {\n        return this.attr('data-' + name)\n    } else {\n        this.attr('data-' + name, val)\n    }\n}\n\n$scope.refresh({\n    msg: '一点测试文本，没有别的意思',\n    title: '啊,title',\n    directive: 'css-color:theColor;css-fontSize:size;'\n})\n\n//自定义指令，如果也按照getter \u0026\u0026 setter设计，也能获取数据\n$('body').append(JSON.stringify($scope.collect()))\n\nsetTimeout(function() {\n    \n    //directive不会刷新到视图中，因为新的实例不具备setData方法\n    //但是，它会成为dom.setData的属性值，这是需要注意的点\n    $('#scope').refresh({\n        msg: '我是原型方法，所以全局通用，新实例也能调用我',\n        directive: 'new directive'\n    })\n    \n    //从视图中获取数据，也可以获取属性的，所以directive值还是能从dom.setData中得到\n    $('body')\n        .append('\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e')\n        .append(JSON.stringify($('#scope').collect()))\n}, 3000)\n\n```\n\n### 动态调用指令\n\n`jplus`提供了`invoke`方法，提供动态用功能，有两种用法\n\n```javascript\n//单个调用\n$scope.invoke('html', '\u003cp\u003esome text\u003c/p\u003e')\n\n//多个调用\n$scope.invoke({\n\thtml: '\u003cp\u003esome word\u003c/p\u003e',\n\tcss: ['color', '#999'], //多个参数打包成数组形式\n\tattr: ['title', 'a title']\n})\n```\n\n\n```html\n\u003cdiv id=\"scope\"\u003e\n    \u003cinput type=\"text\" data-bind=\"invoke:text\" /\u003e\n\u003c/div\u003e\n```\n\n```javascript\nvar count = 0\nvar timer = setInterval(function() {\n    var data = [{\n            text: {\n                'val': count - 1,\n                'attr': ['title', count - 1]\n            }\n        },{\n            text: {\n                'css': ['font-size', count]\n            }\n        }]\n    $('#scope').refresh(data[count % 2])\n   count++\n   if (count === 100) {\n       clearInterval(timer)\n   }\n}, 300)\n```\n\n### 将`data-bind`拆分为`data-get`和`data-set`\n\n```javascript\n//jplus 源码如下。修改属性值即可\n$.directive = {\n\tgetter: 'data-bind', //对应获取数据\n\tsetter: 'data-bind' //对应刷新视图\n}\n\n//修改\n$.directive.getter = 'data-get'\n$.directive.setter = 'data-set'\n```\n\n### 获取视图模型\n\n在`jplus`中，视图模型是指从作用域扫描出来的特定结构的指令和`dom元素`，本质是一个`object`对象\n\n```javascript\n//获取视图模型\n$scope.scan()\n\n//以特定的html属性作为指令来源，不会改变$.directive.getter || $.directive.setter\n//从data-js属性中得到指令集\n$scope.scan('data-js')\n\n//第二个参数传true时，$scope本身的'data-js'属性将被忽略\n$scope.scan('data-js', true)\n```\n\n### 指定视图中需要获取的数据\n\n`$.fn.collect`接受两个参数，第一个参数为`object`对象，第二个参数为`string`类型，将作为第一个参数传入`$.fn.scan`\n\n```javascript\n//只收集'dataName'，并且指定'data-collect'为指令来源，而非扫描'data-bind'\n$scope.collect({\n    'dataName': 'dataName'\n}, 'data-collect')\n\n\n//只收集'dataName'，并且改变数据结构，将值存储到新对象的data.name属性中，如：{data:{name:value}}\n$scope.collect({\n    'dataName': 'data.name'\n})\n\n//jplus所有支持字符串属性名的地方，都可以用点操作符\n$scope.collect({\n    'a.b.c.e.f': 'a.f'\n})\n\n```\n\n### 指定html属性作为指令来源刷新视图或获取数据\n\n`$.fn.refresh`与'$.fn.collect'的第二个参数，可以指定本次刷新视图或获取数据的指令来源\n\n```javascript\n//指定data-a为指令来源，刷新视图\n$scope.refresh(data, 'data-a')\n\n//指定data-b为指令来源，获取数据\n$scope.collect(null, 'data-b')\n```\n\n### 获取视图中的嵌套数据\n\n渲染嵌套数据到视图的方法是，将`refresh`写在指令中，它只是`setter`；因此获取嵌套数据时，应用`vm`替代\n\n`vm`方法是一个按照`既是setter，也是getter`设计的API。\n\n```javascript\n//jplus源码\n$.fn.vm = function(dataModel) {\n    return isObj(dataModel) ? this.refresh(dataModel) : this.collect()\n}\n```\n\n沿用渲染嵌套数据到视图的例子，稍作修改，就能改造成`get/set`模式\n\n\n```html\n\u003cdiv id=\"scope\"\u003e\n    \u003cul\u003e\n        \u003c!--没有noscan属性的话，classTitle和content也会被抽取出来，跟classList平级--\u003e\n        \u003cli data-bind=\"vm:classList\" noscan\u003e\n            \u003ch3 data-bind=\"text:classTitle\"\u003e\u003c/h3\u003e\n            \u003cul\u003e\n                \u003cli data-bind=\"text:content\"\u003e\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/li\u003e\n    \u003c/ul\u003e\n\u003c/div\u003e\n```\n\n```javascript\nvar data = {\n    classList:[{\n        classTitle:'类名1',\n        content:[1, 2, 3, 4, 5]\n    },{\n        classTitle:'类名2',\n        content:[6, 7, 8, 9, 10]\n    },{\n        classTitle:'类名3',\n        content:[11, 12, 13, 14, 15]\n    },{\n        classTitle:'类名4',\n        content:[16, 17, 18, 19, 20]\n    },{\n        classTitle:'类名5',\n        content:[21, 22, 23, 24, 25]\n    }]\n}\n\n$('#scope').refresh(data)\n\n//只该了html属性，就可以直接用$.fn.collect获取数据了\n$('body').append(JSON.stringify($('#scope').collect()))\n\nconsole.log($('#scope').collect())\n```\n\n[jplus]:https://github.com/Lucifier129/jplus\n[微博]:http://weibo.com/islucifier\n[Github]:https://github.com/Lucifier129\n[在线教程与案例]:http://lucifier129.github.io/jplus2/m/index.html","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucifier129%2Fjplus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flucifier129%2Fjplus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucifier129%2Fjplus/lists"}