VueJSソースの学習——ツールの種類の関数の実現(二)
7158 ワード
原文の住所項目の住所
ツールクラス
domクラス
dom要素挿入削除置換操作
JQに慣れていますが、元の関数で元素をどうやって追加するか覚えていますか?
DcumentFragment
詳細はMDNドキュメントを参照できます.
元素のライフサイクル相関関数
env類
envはブラウザ環境ですか?IEに属しますかアンドロイド?css transitionとanimationはwebkitプレフィックスが必要ですか?
オプティクス類
stratsクラスを実現しましたが、具体的にどこに使うかはまだ分かりません.
ツールクラス
/**
* Simple bind, faster than native
*
* @param {Function} fn
* @param {Object} ctx
* @return {Function}
*/
export function bind (fn, ctx) {
return function (a) {
var l = arguments.length
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
}
結合関数は、appyとcall法を用いてthisの結合を行います./**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
*
* @param {*} a
* @param {*} b
* @return {Boolean}
*/
export function looseEqual (a, b) {
/* eslint-disable eqeqeq */
return a == b || (
isObject(a) && isObject(b)
? JSON.stringify(a) === JSON.stringify(b)
: false
)
debugクラスimport config from '../config'
let warn
if (process.env.NODE_ENV !== 'production') {
const hasConsole = typeof console !== 'undefined'
warn = function (msg, e) {
if (hasConsole && (!config.silent || config.debug)) {
console.warn('[Vue warn]: ' + msg)
/* istanbul ignore if */
if (config.debug) {
if (e) {
throw e
} else {
console.warn((new Error('Warning Stack Trace')).stack)
}
}
}
}
}
export { warn }
debug類は、環境が生産環境かどうかによって決まるという意味があります.domクラス
dom要素挿入削除置換操作
JQに慣れていますが、元の関数で元素をどうやって追加するか覚えていますか?
/**
* Insert el before target
*
* @param {Element} el
* @param {Element} target
*/
export function before (el, target) {
target.parentNode.insertBefore(el, target)
}
/**
* Insert el after target
*
* @param {Element} el
* @param {Element} target
*/
export function after (el, target) {
if (target.nextSibling) {
before(el, target.nextSibling)
} else {
target.parentNode.appendChild(el)
}
}
/**
* Remove el from DOM
*
* @param {Element} el
*/
export function remove (el) {
el.parentNode.removeChild(el)
}
/**
* Prepend el to target
*
* @param {Element} el
* @param {Element} target
*/
export function prepend (el, target) {
if (target.firstChild) {
before(el, target.firstChild)
} else {
target.appendChild(el)
}
}
/**
* Replace target with el
*
* @param {Element} target
* @param {Element} el
*/
export function replace (target, el) {
var parent = target.parentNode
if (parent) {
parent.replaceChild(el, target)
}
}
要素クラスの追加削除/**
* Add class with compatibility for IE & SVG
*
* @param {Element} el
* @param {Strong} cls
*/
export function addClass (el, cls) {
if (el.classList) {
el.classList.add(cls)
} else {
var cur = ' ' + (el.getAttribute('class') || '') + ' '
if (cur.indexOf(' ' + cls + ' ') < 0) {
el.setAttribute('class', (cur + cls).trim())
}
}
}
/**
* Remove class with compatibility for IE & SVG
*
* @param {Element} el
* @param {Strong} cls
*/
export function removeClass (el, cls) {
if (el.classList) {
el.classList.remove(cls)
} else {
var cur = ' ' + (el.getAttribute('class') || '') + ' '
var tar = ' ' + cls + ' '
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ')
}
el.setAttribute('class', cur.trim())
}
if (!el.className) {
el.removeAttribute('class')
}
}
要素のクラスに対する操作は古いバージョンではsetAttributeのみをサポートしていますが、バージョンが更新されるにつれて、ブラウザはクラスList属性のaddとremove方法をサポートして要素のクラスを操作します.DcumentFragment
/**
* Extract raw content inside an element into a temporary
* container div
*
* @param {Element} el
* @param {Boolean} asFragment
* @return {Element}
*/
export function extractContent (el, asFragment) {
var child
var rawContent
/* istanbul ignore if */
if (
isTemplate(el) &&
el.content instanceof DocumentFragment
) {
el = el.content
}
if (el.hasChildNodes()) {
trimNode(el)
rawContent = asFragment
? document.createDocumentFragment()
: document.createElement('div')
/* eslint-disable no-cond-assign */
while (child = el.firstChild) {
/* eslint-enable no-cond-assign */
rawContent.appendChild(child)
}
}
return rawContent
}
DcumentFragmentインターフェースは、親レベルのファイルがない最小の文書オブジェクトを表しています.これは軽量バージョンとしてDockmentとして使用されています.レイアウトされたXMLセグメントまたはまだ整理されていないフォーマットを格納するために使用されます.最大の違いは、DcumentFragmentが実際のDOMツリーの一部ではないためで、その変化はDOMツリーの再レンダリング操作や性能に影響を与える問題がないからです.詳細はMDNドキュメントを参照できます.
元素のライフサイクル相関関数
import { removeWithTransition } from '../transition/index'
....
/**
* Map a function to a range of nodes .
*
* @param {Node} node
* @param {Node} end
* @param {Function} op
*/
export function mapNodeRange (node, end, op) {
var next
while (node !== end) {
next = node.nextSibling
op(node)
node = next
}
op(end)
}
/**
* Remove a range of nodes with transition, store
* the nodes in a fragment with correct ordering,
* and call callback when done.
*
* @param {Node} start
* @param {Node} end
* @param {Vue} vm
* @param {DocumentFragment} frag
* @param {Function} cb
*/
export function removeNodeRange (start, end, vm, frag, cb) {
var done = false
var removed = 0
var nodes = []
mapNodeRange(start, end, function (node) {
if (node === end) done = true
nodes.push(node)
removeWithTransition(node, vm, onRemoved)
})
function onRemoved () {
removed++
if (done && removed >= nodes.length) {
for (var i = 0; i < nodes.length; i++) {
frag.appendChild(nodes[i])
}
cb && cb()
}
}
}
二つの関数は、一定の範囲の要素を削除することによって実現されます.env類
envはブラウザ環境ですか?IEに属しますかアンドロイド?css transitionとanimationはwebkitプレフィックスが必要ですか?
/**
* Defer a task to execute it asynchronously. Ideally this
* should be executed as a microtask, so we leverage
* MutationObserver if it's available, and fallback to
* setTimeout(0).
*
* @param {Function} cb
* @param {Object} ctx
*/
export const nextTick = (function () {
var callbacks = []
var pending = false
var timerFunc
function nextTickHandler () {
pending = false
var copies = callbacks.slice(0)
callbacks = []
for (var i = 0; i < copies.length; i++) {
copies[i]()
}
}
/* istanbul ignore if */
if (typeof MutationObserver !== 'undefined') {
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(counter)
observer.observe(textNode, {
characterData: true
})
timerFunc = function () {
counter = (counter + 1) % 2
textNode.data = counter
}
} else {
timerFunc = setTimeout
}
return function (cb, ctx) {
var func = ctx
? function () { cb.call(ctx) }
: cb
callbacks.push(func)
if (pending) return
pending = true
timerFunc(nextTickHandler, 0)
}
})()
最後のnextTickの実現についてはまだ分かりません.オプティクス類
stratsクラスを実現しましたが、具体的にどこに使うかはまだ分かりません.