这篇依然是跟
相关的方法,侧重点是操作样式的方法。
- dom
读 Zepto 源码系列文章已经放到了 github 上,欢迎 star: reading-zepto
本文阅读的源码为 zepto1.2.0
- classCache= {}
- function classRE(name){
- returnnameinclassCache?classCache[name] : (classCache[name]= new RegExp('(^|\\s)' +name+ '(\\s|$)'))}
这个函数是用来返回一个正则表达式,这个正则表达式是用来匹配元素的
名的,匹配的是如
- class
这样的字符串。
- className1 className2 className3
初始化时是一个空对象,用
- calssCache
用为
- name
,如果正则已经生成过,则直接从
- key
中取出对应的正则表达式。
- classCache
否则,生成一个正则表达式,存储到
中,并返回。
- classCache
来看一下这个生成的正则,
匹配的是开头或者空白(包括空格、换行、tab 缩进等),然后连接指定的
- '(^|\\s)'
,再紧跟着空白或者结束。
- name
- cssNumber = {
- 'column-count': 1,
- 'columns': 1,
- 'font-weight': 1,
- 'line-height': 1,
- 'opacity': 1,
- 'z-index': 1,
- 'zoom': 1
- }
- function maybeAddPx(name, value) {
- return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px": value
- }
在给属性设置值时,猜测所设置的属性可能需要带
单位时,自动给值拼接上单位。
- px
是不需要设置
- cssNumber
的属性值,所以这个函数里首先判断设置的值是否为
- px
类型,如果是,并且需要设置的属性不在
- number
中时,给值拼接上
- cssNumber
单位。
- px
- elementDisplay= {}
- function defaultDisplay(nodeName){
- varelement,displayif(!elementDisplay[nodeName]){element= document.createElement(nodeName)document.body.appendChild(element)
- display= getComputedStyle(element, '').getPropertyValue("display")element.parentNode.removeChild(element)
- display== "none" &&(display= "block")
- elementDisplay[nodeName]=display}
- returnelementDisplay[nodeName]}
先透露一下,这个方法是给
用的,
- .show()
方法需要将元素显示出来,但是要显示的时候能不能直接将
- show
设置成
- display
呢?显然是不行的,来看一下
- block
的可能会有那些值:
- display
- display:none
- display:inline
- display:block
- display:contents
- display:list-item
- display:inline-block
- display:inline-table
- display:table
- display:table-cell
- display:table-column
- display:table-column-group
- display:table-footer-group
- display:table-header-group
- display:table-row
- display:table-row-group
- display:flex
- display:inline-flex
- display:grid
- display:inline-grid
- display:ruby
- display:ruby-base
- display:ruby-text
- display:ruby-base-container
- display:ruby-text-container
- display:run-indisplay:inherit
- display:initial
- display:unset
如果元素原来的
值为
- display
,调用
- table
后变成
- show
了,那页面的结构可能就乱了。
- block
这个方法就是将元素显示时默认的
值缓存到
- display
,并返回。
- elementDisplay
函数用节点名
为
- nodeName
,如果该节点显示时的
- key
值已经存在,则直接返回。
- display
- element= document.createElement(nodeName)document.body.appendChild(element)
否则,使用节点名创建一个空元素,并且将元素插入到页面中
- display= getComputedStyle(element, '').getPropertyValue("display")element.parentNode.removeChild(element)
调用
方法,获取到元素显示时的
- getComputedStyle
值。获取到值后将所创建的元素删除。
- display
- display== "none" &&(display= "block")
- elementDisplay[nodeName]=display
如果获取到的
值为
- display
,则将显示时元素的
- none
值默认为
- display
。然后将结果缓存起来。
- block
的默认值为
- display
? Are you kiding me ? 真的有这种元素吗?还真的有,像
- none
、
- style
和
- head
等元素的默认值都是
- title
。将
- none
和
- style
的
- head
设置为
- display
,并且将
- block
的
- style
属性设置为
- contenteditable
,
- true
就显示出来了,直接在页面上一边敲样式,一边看效果,爽!!!
- style
关于元素的
默认值,可以看看这篇文章 Default CSS Display Values for Different HTML Elements
- display
- function funcArg(context,arg,idx,payload){
- return isFunction(arg)? arg.call(context,idx,payload) : arg}
这个函数要注意,本篇和下一篇介绍的绝大多数方法都会用到这个函数。
例如本篇将要说到的
和
- addClass
等方法的参数可以为固定值或者函数,这些方法的参数即为形参
- removeClass
。
- arg
当参数
为函数时,调用
- arg
的
- arg
方法,将上下文
- call
,当前元素的索引
- context
和原始值
- idx
作为参数传递进去,将调用结果返回。
- payload
如果为固定值,直接返回
- arg
- function className(node,value){
- varklass= node.className || '',svg=klass&& klass.baseVal !== undefined
- if(value=== undefined)returnsvg? klass.baseVal: klass
- svg?(klass.baseVal =value) : (node.className =value)}
包含两个参数,为元素节点
- className
和需要设置的样式名
- node
。
- value
如果
不为
- value
(可以为空,注意判断条件为
- undefined
,用了全等判断),则将元素的
- value === undefined
设置为给定的值,否则将元素的
- className
值返回。
- className
这个函数对
的元素做了兼容,如果元素的
- svg
属性存在,并且
- className
属性存在
- className
时,为
- baseVal
元素,如果是
- svg
元素,取值和赋值都是通过
- svg
。对
- baseVal
不是很熟,具体见文档: SVGAnimatedString.baseVal
- svg
- css: function(property,value){
- if(arguments.length < 2){
- varelement= this[0]if(typeofproperty== 'string'){
- if(!element)return
- return element.style[camelize(property)]|| getComputedStyle(element, '').getPropertyValue(property)} else if(isArray(property)){
- if(!element)return
- varprops= {}
- varcomputedStyle= getComputedStyle(element, '')$.each(property, function(_,prop){props[prop]=(element.style[camelize(prop)]|| computedStyle.getPropertyValue(prop))})returnprops}
- }
- varcss= ''
- if(type(property)== 'string'){
- if(!value&&value!== 0)this.each(function(){ this.style.removeProperty(dasherize(property))})elsecss= dasherize(property)+ ":" + maybeAddPx(property,value)} else {
- for(keyinproperty)if(!property[key]&&property[key]!== 0)this.each(function(){ this.style.removeProperty(dasherize(key))})elsecss+= dasherize(key)+ ':' + maybeAddPx(key,property[key])+ ';'
- }
- return this.each(function(){ this.style.cssText += ';' +css})}
方法有两个参数,
- css
是的
- property
样式名,
- css
是需要设置的值,如果不传递
- value
值则为取值操作,否则为赋值操作。
- value
来看看调用方式:
- css(property)⇒value // 获取值
- css([property1, property2, ...])⇒object // 获取值
- css(property, value)⇒self // 设置值
- css({
- property: value,
- property2: value2,
- ...
- })⇒self // 设置值
下面这段便是处理获取值情况的代码:
- if(arguments.length < 2){
- varelement= this[0]if(typeofproperty== 'string'){
- if(!element)return
- return element.style[camelize(property)]|| getComputedStyle(element, '').getPropertyValue(property)} else if(isArray(property)){
- if(!element)return
- varprops= {}
- varcomputedStyle= getComputedStyle(element, '')$.each(property, function(_,prop){props[prop]=(element.style[camelize(prop)]|| computedStyle.getPropertyValue(prop))})returnprops}
- }
当为获取值时,
方法必定只传递了一个参数,所以用
- css
来判断,用
- arguments.length < 2
方法来获取值,获取的是集合中第一个元素对应的样式值。
- css
- if(!element)return
- return element.style[camelize(property)]|| getComputedStyle(element, '').getPropertyValue(property)
当
为
- property
时,如果元素不存在,直接
- string
掉。
- return
如果
中存在对应的样式值,则优先获取
- style
中的样式值,否则用
- style
获取计算后的样式值。
- getComputedStyle
为什么不直接获取计算后的样式值呢?因为用
获取的样式值是原始的字符串,而
- style
顾名思义获取到的是计算后的样式值,如
- getComputedStyle
用
- style = "transform: translate(10px, 10px)"
获取到的值为
- style.transform
,而用
- translate(10px, 10px)
获取到的是
- getComputedStyle
。这里用到的
- matrix(1, 0, 0, 1, 10, 10)
方法是将属性
- camelize
转换成驼峰式的写法,该方法在《读 Zepto 源码之内部方法》有过分析。
- property
- else if(isArray(property)){
- if(!element)return
- varprops= {}
- varcomputedStyle= getComputedStyle(element, '')$.each(property, function(_,prop){props[prop]=(element.style[camelize(prop)]|| computedStyle.getPropertyValue(prop))})returnprops}
如果参数
为数组时,表示要获取一组属性的值。
- property
方法也在《读 Zepto 源码之内部方法》有过分析。
- isArray
获取的方法也很简单,遍历
,获取
- property
上对应的样式值,如果
- style
上的值不存在,则通过
- style
来获取,返回的是以样式名为
- getComputedStyle
,
- key
为对应的样式值的对象。
- value
接下来是给所有元素设置值的情况:
- var css = ''
- if (type(property) == 'string') {
- if (!value && value !== 0) this.each(function() {
- this.style.removeProperty(dasherize(property))
- })
- else css = dasherize(property) + ":" + maybeAddPx(property, value)
- } else {
- for (key in property) if (!property[key] && property[key] !== 0) this.each(function() {
- this.style.removeProperty(dasherize(key))
- })
- else css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
- }
- return this.each(function() {
- this.style.cssText += ';' + css
- })
这里定义了个变量
来接收需要新值的样式字符串。
- css
- if(type(property)== 'string'){
- if(!value&&value!== 0)this.each(function(){ this.style.removeProperty(dasherize(property))})elsecss= dasherize(property)+ ":" + maybeAddPx(property,value)}
当参数
为字符串时
- property
如果
不存在并且值不为
- value
时(注意,
- 0
为
- value
时,已经在上面处理过了,也即是获取样式值),遍历集合,将对应的样式值从
- undefined
中删除。
- style
否则,拼接样式字符串,拼接成如
形式的字符串。这里调用了
- width:100px
的方法,自动给需要加
- maybeAddPx
的属性值拼接上了
- px
单位。
- px
跟
- this.css('width', 100)
会得到一样的结果。
- this.css('width', '100px')
- for(keyinproperty)if(!property[key]&&property[key]!== 0)this.each(function(){ this.style.removeProperty(dasherize(key))})elsecss+= dasherize(key)+ ':' + maybeAddPx(key,property[key])+ ';'
当
为
- property
是样式名,
- key
为样式值的对象时,用
- value
遍历对象,接下来的处理逻辑跟
- for...in
为
- property
时差不多,在做
- string
拼接时,在末尾加了
- css
,避免遍历时,将样式名和值连接在了一起。
- ;
- hide: function() {
- return this.css("display", "none")
- },
将集合中所有元素的
样式属性设置为
- display
,就达到了隐藏元素的目的。注意,
- node
方法中已经包含了
- css
循环。
- each
- show: function(){
- return this.each(function(){
- this.style.display == "none" &&(this.style.display = '')if(getComputedStyle(this, '').getPropertyValue("display")== "none")this.style.display = defaultDisplay(this.nodeName)})},
方法是直接将
- hide
设置为
- display
即可,
- none
可不可以直接将需要显示的元素的
- show
设置为
- display
呢?
- block
这样在大多数情况下是可以的,但是碰到像
、
- table
等显示时
- li
默认值不是
- display
的元素,强硬将它们的
- block
属性设置为
- display
,可能会更改他们的默认行为。
- block
要让元素真正显示,要经过两步检测:
- show
- this.style.display == "none" &&(this.style.display = '')
如果
中的
- style
属性为
- display
,先将
- none
中的
- style
置为 ``。
- display
- if(getComputedStyle(this, '').getPropertyValue("display")== "none")this.style.display = defaultDisplay(this.nodeName)
- })
这样还未完,内联样式的
属性是置为空了,但是如果嵌入样式或者外部样式表中设置了
- display
为
- display
的样式,或者本身的
- none
默认值就是
- display
的元素依然显示不了。所以还需要用获取元素的计算样式,如果为
- none
,则将
- none
的属性设置为元素显示时的默认值。如
- display
元素的
- table
中的
- style
属性值会被设置为
- display
。
- table
- toggle: function(setting){
- return this.each(function(){
- varel= $(this);(setting=== undefined ? el.css("display")== "none": setting)? el.show():el.hide()})},
切换元素的显示和隐藏状态,如果元素隐藏,则显示元素,如果元素显示,则隐藏元素。可以用参数
指定
- setting
的行为,如果指定为
- toggle
,则显示,如果为
- true
(
- false
不一定为
- setting
),则隐藏。
- Boolean
注意,判断条件是
,用了全等,只有在不传参,或者传参为
- setting === undefined
的时候,条件才会成立。
- undefined
- hasClass: function(name) {
- if (!name) return false
- return emptyArray.some.call(this,
- function(el) {
- return this.test(className(el))
- },
- classRE(name))
- },
判断集合中的元素是否存在指定
的
- name
名。
- class
如果没有指定
参数,则直接返回
- name
。
- false
否则,调用
方法,生成检测样式名的正则,传入数组方法
- classRE
,要注意,
- some
里面的
- some
值并不是遍历的当前元素,而是传进去的
- this
正则,回调函数中的
- classRE(name)
才是当前元素。具体参考文档 Array.prototype.some()
- el
调用
方法,获取当前元素的
- className
值,如果有一个元素匹配了正则,则返回
- className
。
- true
- addClass: function(name){
- if(!name)return this
- return this.each(function(idx){
- if(!('className' in this))returnclassList=[]varcls= className(this),newName= funcArg(this,name,idx,cls)newName.split(/\s+/g).forEach(function(klass){
- if(!$(this).hasClass(klass))classList.push(klass)}, this)classList.length && className(this,cls+(cls? " ":"")+ classList.join(" "))})},
为集合中的所有元素增加指定类名
。
- name
可以为固定值或者函数。
- name
如果
没有传递,则返回当前集合
- name
,以进行链式操作。
- this
如果
存在,遍历集合,判断当前元素是否存在
- name
属性,如果不存在,立即退出循环。要注意,在
- className
遍历中,
- each
指向的是当前元素。
- this
- classList=[]varcls= className(this),newName= funcArg(this,name,idx,cls)
用来接收需要增加的样式类数组。不太明白为什么要用全局变量
- classList
来接收,用局部变量不是更好点吗?
- classList
保存当前类的字符串,使用函数
- cls
获得。
- className
是需要新增的样式类字符串,因为
- newName
可以是函数或固定值,统一交由
- name
来处理。
- funcArg
- newName.split(/\s+/g).forEach(function(klass){
- if(!$(this).hasClass(klass))classList.push(klass)}, this)classList.length && className(this,cls+(cls? " ":"")+ classList.join(" "))
是将
- newName.split(/\s+/g)
字符串,用空白分割成数组。
- newName
再对数组遍历,得到单个类名,调用
判断类名是否已经存在于元素的
- hasClass
中,如果不存在,将类名
- className
进数组
- push
中。
- classList
如果
不为空,则调用
- classList
方法给元素设置值。
- className
是将类名转换成用空格分隔的字符串,如果
- classList.join(" ")
即元素原来就存在有其他类名,拼接时也使用空格分隔开。
- cls
- removeClass: function(name){
- return this.each(function(idx){
- if(!('className' in this))return
- if(name=== undefined)return className(this, '')
- classList= className(this)funcArg(this,name,idx
来源: http://www.cnblogs.com/hefty/p/6984688.html