Last time we looked at the source code for the element selector, attR, and class. Today we’ll look at how the append and other operations work.

clone: function(){
  return this.map(function(){ return this.cloneNode(true)})}Copy the code

This.clonenode (flag) It returns a copy of this. Flag true indicates deep cloning. For compatibility, this flag is recommended.

children: function(selector){
  return filtered(this.map(function(){ return children(this) }), selector)
}
function filtered(nodes, selector) {
// When selector is not empty.
  return selector == null ? $(nodes) : $(nodes).filter(selector)
}
function children(element) {
// For compatibility
  return 'children' in element ?
// Return elements of a Node. In IE8, comment nodes are included.
// But that method is not called here.
    slice.call(element.children) :
// Children are not supported
    $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
}
filter: function(selector){
  if (isFunction(selector)) return this.not(this.not(selector))
  return $(filter.call(this.function(element){
    return zepto.matches(element, selector)
  }))
}
// This is also an important point
zepto.matches = function(element, selector) {
  if(! selector || ! element || element.nodeType ! = =1) return false
  var matchesSelector = element.matches || element.webkitMatchesSelector ||
                        element.mozMatchesSelector || element.oMatchesSelector ||
                        element.matchesSelector
  if (matchesSelector) return matchesSelector.call(element, selector)
  varmatch, parent = element.parentNode, temp = ! parentif (temp) (parent = tempParent).appendChild(element)
  match = ~zepto.qsa(parent, selector).indexOf(element)
  temp && tempParent.removeChild(element)
  return match
}Copy the code

The ‘children’ in element in the children method is used to check whether the browser supports the children method. Children is compatible with IE9. Element.matches(selectorString) returns true if the Element is selected by the specified selectorString, otherwise selectorString is a CSS selectorString. This method has good compatibility with element. Matches, and is safe to use on mobile, although on older versions you can’t avoid adding prefixes. Such as element. Matches | | element. WebkitMatchesSelector | | element. MozMatchesSelector | | element. OMatchesSelector | | element. MatchesSelector.

Note: This method can also be polyfilled in IE8, as shown below:

if(! Element.prototype.matches) { Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector ||function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length;
            while (--i >= 0&& matches.item(i) ! = =this) {}
            return i > - 1;
        };
}Copy the code

The children method, as shown above, simply calls several different functions internally.

closest

closest: function(selector, context){
  var nodes = [], collection = typeof selector == 'object' && $(selector)
  this.each(function(_, node){
// When a node exists (the collection has a node element or node matches a selector)
    while(node && ! (collection ? collection.indexOf(node) >=0 : zepto.matches(node, selector)))
// If a context is given, node cannot equal that context
// Note that if node===context or isDocument is true, node is falsenode = node ! == context && ! isDocument(node) && node.parentNodeif (node && nodes.indexOf(node) < 0) nodes.push(node)
  })
  return $(nodes)
}
// Check if it is a document node
/ / DOCUMENT_NODE more usage can go to https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeType
function isDocument(obj)
  { returnobj ! =null && obj.nodeType == obj.DOCUMENT_NODE }Copy the code

after prepend before append

In these methods, the content is generated into A DOM node by calling the Zepto. fragment method, and then the insertion action is performed. Also note that the content passed in can be an HTML string, A DOM node, or an array of nodes, as follows:

This is a DOM node

This is a DOM node

var adjacencyOperators = [ 'after'.'prepend'.'before'.'append' ];
adjacencyOperators.forEach(function(operator, operatorIndex) {
// Prepend and append inside is 1
  var inside = operatorIndex % 2
  $.fn[operator] = function(){
    var argType, nodes = $.map(arguments.function(arg) {
          var arr = []
Var arg = document.createElement('span'); The div type is object
//var arg = $('div'), which is array
//var arg = '
      
this is a div
', in which case the type is string
argType = type(arg) // When passed as an array if (argType == "array") { arg.forEach(function(el) { if(el.nodeType ! = =undefined) return arr.push(el) else if ($.zepto.isZ(el)) return arr = arr.concat(el.get()) arr = arr.concat(zepto.fragment(el)) }) return arr } return argType == "object" || arg == null ? arg : zepto.fragment(arg) }), parent, copyByClone = this.length > 1 if (nodes.length < 1) return this return this.each(function(_, target){ // Parent is target when it is prepend and append parent = inside ? target : target.parentNode // Change all actions to before, which only changes the difference between parent and target target = operatorIndex == 0 ? target.nextSibling : operatorIndex == 1 ? target.firstChild : operatorIndex == 2 ? target : null // Check if parent is in document var parentInDocument = $.contains(document.documentElement, parent) nodes.forEach(function(node){ if (copyByClone) node = node.cloneNode(true) else if(! parent)return $(node).remove() // parent.insertbefore (node,parent) inserts a child before one of the children of the current node // If parent is null, node is inserted at the end of the child node. If a node is already in the DOM tree, the node is removed from the DOM tree first parent.insertBefore(node, target) // If the parent is in the document, the traverseNode is called to process the node and all of its children. Check whether node or its children are script and have no SRC address. if (parentInDocument) traverseNode(node, function(el){ if(el.nodeName ! =null && el.nodeName.toUpperCase() === 'SCRIPT'&& (! el.type || el.type ==='text/javascript') && !el.src){ // Since there are separate window objects in iframe // Also, since insertBefore inserts the script, it does not execute the script, so it is set in the form of evel. var target = el.ownerDocument ? el.ownerDocument.defaultView : window target['eval'].call(target, el.innerHTML) } }) }) }) } Before, append, insertBefore, insertAfter, and prependTo. The core is similar. $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ $(html)[operator](this) return this } }) zepto.fragment = function(html, name, properties) { var dom, nodes, container, containers = { 'tr': document.createElement('tbody'), 'tbody': table, 'thead': table, 'tfoot': table, 'td': tableRow, 'th': tableRow, The '*': document.createElement('div') }, singleTagRE = /^<(\w+)\s*\/? > (? : < 1 > \ / \ |) $/, tagExpanderRE = / ]*)\/>/ig // Dom is a p element if it contains only one node, with no text nodes or child nodes, like

.
if (singleTagRE.test(html)) dom = $(document.createElement(RegExp. $1)) if(! dom) {// Fix HTML, if it is

fix it to

if (html.replace) html = html.replace(tagExpanderRE, "< > $1 < / a > $2") // Set the name of the label. if (name === undefined) name = fragmentRE.test(html) && RegExp. $1 if(! (namein containers)) name = The '*' container = containers[name] container.innerHTML = ' ' + html dom = $.each(slice.call(container.childNodes), function(){ // Remove a node from the DOM and return the deleted node container.removeChild(this)})}// Check if the attribute is an object. If it is an object, set the attribute to the element. if (isPlainObject(properties)) { nodes = $(dom) $.each(properties, function(key, value) { if (methodAttributes.indexOf(key) > - 1) nodes[key](value) else nodes.attr(key, value) }) } return dom }Copy the code

css

css: function(property, value){
// when reading CSS styles
  if (arguments.length < 2) {
    var element = this[0]
    if (typeof property == 'string') {
      if(! element)return
      return element.style[camelize(property)] || getComputedStyle(element, ' ').getPropertyValue(property)
    } else if (isArray(property)) {
      if(! element)return
      var props = {}
      var computedStyle = getComputedStyle(element, ' ')
      $.each(property, function(_, prop){
        props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
      })
      return props
    }
  }

  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 converts font size to hump name fontSize
camelize = function(str){ return str.replace(+ / - (.). ? /g.function(match, chr){ return chr ? chr.toUpperCase() : ' '})}// Change the hump name to normal CSS :fontSize=>font size
function dasherize(str) {
  return str.replace(/::/g.'/')
         .replace(/([A-Z]+)([A-Z][a-z])/g.'$1 _ $2')
         .replace(/([a-z\d])([A-Z])/g.'$1 _ $2')
         .replace(/_/g.The '-')
         .toLowerCase()
}
// Maybe you need to add 'px' to the log
function maybeAddPx(name, value) {
  return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
}Copy the code

getComputedStyle props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) GetPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue () : getPropertyValue ();

Unlike Style, which is writable and can only fetch CSS styles from the element’s style property, style can fetch all CSS property objects that are ultimately applied to the element. This method is compatible with IE9+, but in IE9 you cannot read pseudo-class CSS.