1 Star 3 Fork 0

timzaak / JSCommonUtil

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

#JSCommonUtil

该项目主要是对于web开发中常用的一些功能进行封装。项目主要包含:

  • 常用javascript类型判定(from avalon)
  • HashMap,Set集合实现,以及常用集合操作(from angular ,it may deprecate in the future)
  • 前端页面渲染流程
  • javascript版本的promise
  • pubsub订阅机制
  • Array函数扩展

PS:一些代码和思路来源于AngularJS avalon, 并加以修改。

项目使用场景

页面模板众多,而又想依赖ajax做单页应用 支持chrome游览器,其他游览器暂时未测试,一般游览器支持Object.keys Array.forEach Array.map ECMA5标准 的,基本上没什么问题

项目依赖

  • jquery

项目开发环境

项目使用grunt作为自动化脚本环境, 使用jasminejasmine-jquery.js作为测试框架,并且做了一些即是demo还是说明的html页面,可供开发参考,由于demo会发送ajax请求views文件夹下的模板,所以需要运行在web容器下面

欢迎fork!

简明教程

当前版本将重点放在模板渲染和模板与模板之间的数据变化相应。

公共函数

jc.util

该对象现有两个常用的函数,暴露出来,以供大家使用 isInDocument isInDocument(parent,child)判定子节点是否存在,(当子节点和传入的父节点是同一个时,返回true), 当参数为一个时,判定该节点是否在当前页面body内 nextUid 在当前页面产生一个唯一的id标识 jc.Array

该对象内封装了多个函数groupBy group objToArr isEqual getIndex contain getDistinct replaceElem.具体说明,可参照src/arrayHelper.js里的注释,用法可参照test/arrayHelperSpec.js ,如果在开发中遇到数据转换的问题,可以使用这个对象内的方法。 groupBy group 两个函数都是用来对数组进行分组的。 objToArr 将object对象的key和value转换成数组。 isEqual 对数组进行深度判定值是否相等。 getIndex 根据提供的参数,数据这个元素在数组中的下表。 contain 判定数组中是否拥有某个元素,支持数组元素是是对象的判定。 getDistinct 数组去重,仅支持Array类型。 replaceElem 根据查找条件找到对象并替换掉 jc.mix

用来做javascript继承(父子继承和数据复制),code from jquery。这个函数在做模板间互动时,会减少一些工作量。 jc.mix(bool,child,parent),bool参数代表着是深度copy,还是浅copy(当parent有个object|array属性时,浅copy会将这个属性引用赋值给子类,而深copy则是遍历父类的集合属性)。 具体如何用,可参考prepareSpec.js中关于该函数的测试用例。

jc.initPB

订阅发布模块,可用来创建自己的一套发布订阅机制,功能会随着版本的叠加而增强。现在还没有过滤器概念。但拥有channel,参考pubsubSpec.js中关于该函数的测试。

jc.getType

从avalon中拿过来的关于类型判定的函数,支持boolean number string function array date regexp object error的类型判定。返回值皆为小写。基本用法为

	if(jc.getType(unKnownType)==='object'){
		//TODO
	}else{
		//TODO
	}

模板数据

在解释模板数据之前,需要解释一个名词模板实例。模板实例是指将模板插入到指定的dom中,并通过数据渲染,这时便成称之为模板实例。一个模板可以有多个实例。模板实例可通过jc.th($jquerySelector)获取。 模板数据,就是和模板实例绑定在一起的数据。通过模板的写,它可以监管模板实例view层变化,并反映在数据中。用户只需要操作模板数据即可,不需要再过多的关注view。模板数据以通过jc.th($jquerySelector).data()获取。 使用JSCommonUtils需要特别关注模板数据的操作与构建,好的模板数据构建会使模板更容易维护。所以,在写模板之前,请一定要思考好模板数据如何构造。jc.mix jc.Array.objToArr函数在构建模板数据时会很有用。

当要更改更改数组中的值时,请使用data.array.set($index,value)方法。这样才会触发变化

模板渲染

jc.render

	jc.render(data,url,$jquerySelector,callback,options)
	
	//data:模板数据
	//url:地址,.html 要省略掉
	//$jquerySelector 要确保选择器选出来的存在且唯一,否则抛出异常
	//callback:回调函数,并为其传递进当前模板实例引用
	//options 暂时还没有用,以后可能会扩展一些函数

整个项目中重要的函数,用来调用模板渲染函数scanNodes以及对模板状态的更新。具体说明可参考src/documentParse.js内关于此函数的注释

注意,jc.render内部执行了异步调用模板ajax请求,所以关于当前模板实例的业务逻辑都需要写到 回调函数中。

dom标签

现在已开发的标签有jc-if jc-repeat jc-reuse jc-bind jc-cal jc-duplex jc-dupfilter jc-value jc-reset jc-attr jc-foreach jc-class, 注意:如果使用了未被定义的标签,会自动调用jc-cal来进行匹配,例如 :

<intput jc-value="..."/>
<intput jc-cal-value="..."/>

这两种使用方式等价

jc-if
<div jc-if='abc'>
	...
</div>
  • jc-if表示是否该div存在于dom中,如果abc为false|undefined|''|0,则会删除此div,且其子元素不会没扫描。
  • jc-if-notjc-if正好相反,如果abc为false|undefined|''|0,则显示该div,并扫描子元素。
  • jc-if-loop 则是和jc-repeat一块使用,可参看关于jc-repeat标签的讲解

jc-if jc-if-not在渲染自由度比较大的模板时,会被大量用到

jc-repeat
<ul>
	<li jc-repeat-elem='arr' jc-if='isShow' jc-if-loop='this.$index%2===0'>{{$index}}: {{elem}}</li>
</ul>

数据

var data={
	arr:[1,2,3],//data:[1,2,3]
	isShow:true
}


//当要渲染上面的li元素时,data会依据当前要渲染的数组元素生成新的数据结构
{
	elem:$arrayData,//data.arr[$index]
	$index:$num,
	$data:data,
	$path:$string,//当前元素索引
	$isForEach:$boolean//当前是否是在渲染repeat元素
}
//来渲染li元素
//如果数组元素是一个object时,会生成下面的数据结构

{
	elem:{
		$objectData,
		$index:$num,
		$path:$string//当前元素索引
	},
	$data:data,
	$isForEach:$boolean//当前是否是在渲染repeat元素
}
//所以,模板数据的key值最好不要以`$`开头,有可能会被框架内部的值覆盖掉

jc-repeat-$param用来循环当前元素。$param用来做模板写数据的索引,以$_或字母开头 在jc-repeat中,包含了额外的元素

  • $index:当前循环到了第几个元素 ,以0开始
  • $path:为当前父索引路径,用户不需要关注它
  • $data:传递给jc.render的模版数据

在使用jc-repeat的时候,会遇到嵌套的情况,请参考test-repeat.html关于jc-repeat使用。需要注意的是:

jc-repeat不支持遍历object,可通过jc.Array.objToArr函数来进行转换。 $param参数不要以$开头,并且最好不要和索引路径同名称 jc-if jc-repeat 是有先后顺序的,先判定 jc-if 是不是要渲染,再来判定 jc-repeat 当使用jc-repeat嵌套时,当嵌套的最里面为一个值数组时,直接使用$index,$path 即可获取值,如果为object数组时,需要elem.$index,elem.$path来获取值。且嵌套的内层可获取外层的值索引,而外层无法获取内层值索引。 当更改集合内的数据时,请使用set($index,$value)方法。例如 {a:[1,2,3]},可以使用a.set(2,5)将数据改为{a:[1,2,5]}。直接使用a[2]=5进行 赋值的话,不会触发响应关于此数据的变化。

jc-foreach

jc-foreach标签是jc-repeat标签的补充,性能上有所下降,能用jc-repeat标签的话,不要使用jc-foreach,`jc-foreach是用来迭代内部元素的,例如,循环dl中的dt dd元素。这种功能是jc-repeat`标签力所不逮的。

<div jc-foreach-e='....'>
	<!--循环内部-->
<div>
jc-cal
<div jc-cal-data='...'>
	
</div>

jc-cal-$any会计算表达式的值,然后以 $any='计算后的结果' 插入到当前元素的attribute中,如果当前dom已有该attribute,会被覆盖掉。 任何未被框架声明处理的jc-$any,都会转化成jc-cal-$any来进行处理

注意:jc-cal-class被做了特殊处理,会以addClass的形式添加进当前对象中,不会进行覆盖

jc-attr

jc-attr-$any和jc-cal标签都是作用在element上的attribute,但jc-attrjc-cal相比,多了模版数据变化触发模版实例变化的功能。

注意: jc-attr 不支持 jc-attr-class 。

jc-value
<input jc-value='data|filter'/>
<textarea jc-value='...'></textarea>

jc-value会和jc-cal-value效果功能差不多,唯一不同的是当在textarea html标签中使用时,jc-cal-val不会起作用(<textarea>{{....}}</textarea>也不会起作用)。

jc-reset
<input jc-reset value='重置'/>
<button jc-reset >重置</button>

jc-reset-$event用来重置当前表单,$event 为触发重置表单的事件,默认为click

请不要使用<input type='reset' value='重置'/>,它不会触发jc-bindjc-duplex标签效果

jc-class
	<div class='afg' jc-class-$any='isOk'>
	</div>

jc-class-$any 是专门为class设计的,当表达式结果为true时,$any就会加到当前元素的class中去,如果为false,则会从中去除$any

jc-reuse
<div jc-reuse='tag1'>
	....
</div>

js

jc.th(...).reRender('tag1',data)

该标签是用来标明其子元素可能会被重新彻底渲染。jc-reuse 标签子元素的html会被缓存起来,并用其属性值作为标记,用户可以使用jc.th(...)reRender来把其重新渲染一边。注意,传递个reRender的值会更改模版数据。该标签是本框架未完善时的过渡标签,以后可能会废弃掉。

jc-bind

jc-bind-$event用在表单元素上,将view层的变化传递给模板数据。$event为触发事件,不写的话,会根据表单元素的不同特性进行默认。且根据表单元素的特点传递给模板数据的值类型也不尽相同,在设计上,尽量符合游览器表单元素基本使用情况。 下面是数据转化:

  • input checked ,input radio =>Boolean
  • input text,input password,select,textarea => string
  • input number => number 触发事件有 mousemove mouseleave等表单事件

input number 如果输入值不正确的话,是不会触发模板数据变化 jc-bind的工作原理,是先判定当前元素的类型,根据类型选定默认触发事件和值处理方法, 然后绑定更改模板数据的函数到该元素上,当事件发生时,便会执行该函数

jc-duplexjc-dupfilter
<input type='text' jc-duplex='a' />
<input type= 'checkbox' jc-duplex='check|sampleMap(true,enable,false,disable)'  jc-checked='check|toBoolean(enable)' jc-dupfilter='|toBoolean(enable)'/>

jc-duplex-$event是在jc-bind的功能之上,做的扩展,支持模板数据变化,触发view层也跟着变化。 如果jc-duplex的表达式使用了过滤器,必须在相同的节点上使用jc-dupfilter用来写反向过滤器,使之view数据和模板数据可以相互转换

用了jc-duplex不需要再写jc-bind标签 关于jc-duplexjc-bind如何使用,请参考test_bind.html和test_duplex.html

表达式

JSCommonUtil默认{{...}} {{#...}}作为表达式在TextNode中的包裹标签,不支持{{...{{...}}...}}嵌套使用,如果想改,可以通过jc.config.interpolate(array)来配置(from avalon), {{...}}仅仅是计算框内的值然后渲染到页面中去,{{#...}}则在会渲染后,会将当前渲染的textNode和模板数据进行绑定,如果模板数据产生了变化,页面也会变化。 关于{{...}}的具体使用,可参考test-textExpression.html文件。

表达式分为两部分,第一部分数值计算-值索引,第二部分过滤器(也可以称之为文本转换器) 用法:{{数值计算-值索引|过滤器1|过滤器2...}}

数值计算-值索引

要想熟练使用,需要理解其原理。

值索引:

//var UniObj ={}

function dotPath(object, path) {
    var re = object;
    path.split(".").forEach(function(v) {
        if (re[v] === undefined) {
            re = UniObj
        } else {
            re = re[v]
        }
    });
    if (re !== UniObj) {
        return re;
    }
}

数值计算:

var noop=function(){}
//value 就是表达式中的第一部分,data为数据
Function.apply(noop, ["return " + value]).call(data)

所以,当使用数值计算模式时,是需据要this关键字来索引数,请注意: jc-duplex,jc-bind 标签不支持数值计算模式

表达式如果是要索引数组数据,会和js数组索引有所区别:

var data={arr:[1,2,3]}
// {{arr.0}} 正确
// {{arr[0]}} 错误
// {{this.arr[0]}} 正确 但是不推荐如此用,性能会降低一些
过滤器

过滤器用来转换表达式第一部分计算结果成其它返回值。过滤器接收参数但会将参数转化为字符串,例如 {{value|defaultVal(默认值)}}默认值会转化成字符串传递进defaultVal过滤器函数。

现在框架内部实现了三个过滤器。

  • defaultVal 当模板数据根据索引找出来的值为undefined或者null时,就会转换为第一个参数。没有参数的话,会默认为空字符串
  • toBoolean 返回true or false ,当有参数的时候,会将索引出来的值和参数做比较,相同,为true,不同为false
  • sampleMap 简单的值映射,可参考上面的例子 。

注意: {{...}}只能在textNode中使用,不能在attribute中使用,而如果在下列 area,base,basefont,br,col,command,embed,hr,img,input, link,meta,param,source,track,wbr,noscript,script,style,textarea html标签内,表达式不会被处理 以后可能会根据需求,将textarea开放出来,现在可用jc-value标签来做关于textarea的开发。

模板实例间的订阅

具体例子可参照常规页面联动.html。如果数据结构比较混乱时,可参照test-th-pb.html

jc.th

jc.th函数会返回一个方法对象,里面提供类似jquery的empty html hide show等方法。

listen

listen($path,$targetDivs,$targetPath) 主要是用来监听其他模板数据变化并更改自己的模板数据,具体参考test-th-pb.html中的用法,这个函数的参数十分灵活,当目标模板实例和原模板实例 模板数据结构相同时, 可以直接listen($path,$targetDivs)使用,$path可以是数据,字符串,object。他们都会在内部被转化成寻址数组

注意:监听数组内的具体数据时,最好再监听下整个数组变化,如果数组被调用Array方法或重新赋值时,通知范畴是以数组为单位的。

bind

bind($path,function,fnName)用来绑定一个function,可以通过对函数命名来分类,方便批量unbind。在绑定函数列表中,他们的执行是按照绑定的先后顺序来执行的。如果出现了bug,可以使用jc.th.$pb.fn.$jcQueuejc.$watchPB.fn.$jcQueue查看当前系统内的函数绑定状态(jc.th($div)._data("id")可以获得模板实例的唯一标识)

unbind

unbind(fnName)解除绑定的函数,当传递进$all时,会删除掉整个绑定在该模板的函数。

reRender *deprecated*

reRender方法要和jc-reuse标签搭配使用,使用jc-reuse表明该元素的子元素会被重用,然后使用reRender方法重新渲染这一块元素。注意,当你 想用该组合时,可以思考有没有更好的写法来替代它。

empty

empty会将当前模版实例从dom中移除掉,并去除响应的事件监听,以达到节约内存的目的

如果模板要清空的话,请使用jc.th($jquerySelect).hide() jc.th($jquerySelect).show()等来操作模板状态的变化。

getCleanData 渲染后的模版数据是有可能含有额外的$index $path值的,如果想获取纯净的数据,直接jc.th($selector).getCleanData()即可

JSCommonUtil扩展

如果需要更改当前dom的,请扩展 jc.scanMod对象,如果是对值进行转换(表达式的过滤器)的,例如将id转换为具体的名称,可扩转jc.filters,如果需要根据当前dom进行模板数据操作,可扩展jc.bindMod。注意: jc-id标签保留,可能会在后面的版本中使用

#####配置

//默认配置
jc.config={
	tplRootUrl:'./views/',//默认取模版的根目录
}

jc.config.interpolate(['{{','}}']) //默认文本计算符

现阶段版本

1.1.0

TODO-1.2.0

  • refactor the implements of subpub to make it support more fixtures, like $broadcast $emit of Angular
  • refactor the tempHelper to make it more easy to understand
  • make this project compatible with IE8-11/firefox
  • kick off jquery
  • kick off jquery ajax, implement a sample ajax and websocket
  • introduce the event system
  • fix array.length=0 bug

Project Thinking

框架写的时候,想的很多,然后写了一些较为复杂的代码,后来才发现,既然用最简单的方法能实现,就不要追求复杂的东西,虽然复杂带来了一些 想像上的性能提升,但随之而来的bug更会让人头疼。所以,code simple to happy!

Copyright (c) 2014 "Cowboy" Ben Alman, contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

基于模板的mv*轻量框架 展开 收起
JavaScript
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/timzaak/JSCommonUtil.git
git@gitee.com:timzaak/JSCommonUtil.git
timzaak
JSCommonUtil
JSCommonUtil
master

搜索帮助