import { utils } from '../utils' ; import { Vnode , IPatchList , TEventType } from './vnode' ; param { Vnode } newVnode param { Vnode } oldVnode param { IPatchList [ ] } patchList param { ( oldVnode : Vnode , newVnode : Vnode ) => boolean } needDiffChildCallback function diffChildNodes ( oldVnode , newVnode , patchList ) { if ( oldVnode . childNodes && oldVnode . childNodes . length > 0 ) { oldVnode . childNodes . forEach ( ( oChild , index ) => { if ( ! oChild . type ) return ; const sameCodeFromNewCode = newVnode . childNodes . find ( nChild => ( nChild . tagName === oChild . tagName && nChild . key === oChild . key && nChild . template === oChild . template && ! nChild . checked ) ) ; if ( ! sameCodeFromNewCode ) { patchList . push ( { type : 0 , parentVnode : oldVnode , changedVnode : oChild , } ) ; } if ( sameCodeFromNewCode ) { const sameCodeFromNewCodeIndex = newVnode . childNodes . findIndex ( nChild => nChild === sameCodeFromNewCode ) ; if ( sameCodeFromNewCodeIndex !== index ) { patchList . push ( { type : 2 , newIndex : sameCodeFromNewCodeIndex , oldIndex : index , parentVnode : oldVnode , changedVnode : oChild , } ) ; } oChild . inComponent = sameCodeFromNewCode . inComponent ; diffVnode ( oChild , sameCodeFromNewCode , patchList ) ; sameCodeFromNewCode . checked = true ; } } ) ; } if ( newVnode . childNodes && newVnode . childNodes . length > 0 ) { newVnode . childNodes . forEach ( ( nChild , index ) => { if ( nChild . checked || ! nChild . type ) return ; patchList . push ( { type : 1 , newIndex : index , parentVnode : oldVnode , changedVnode : nChild , } ) ; nChild . checked = true ; } ) ; newVnode . childNodes . forEach ( nChild => nChild . checked = false ) ; } } param { Vnode } oldVnode param { Vnode } newVnode param { IPatchList [ ] } patchList function diffAttributes ( oldVnode , newVnode , patchList ) { if ( newVnode . attributes && newVnode . attributes . length > 0 ) { newVnode . attributes . forEach ( ( attr ) => { const oldVnodeAttr = oldVnode . attributes . find ( oldAttr => oldAttr . type === attr . type && oldAttr . name === attr . name ) ; if ( ! oldVnodeAttr ) { patchList . push ( { type : 4 , originVnode : oldVnode , changedValue : attr , attributeType : attr . type , } ) ; } if ( oldVnodeAttr && ( ( attr . type === 'attribute' && oldVnodeAttr . value !== attr . value ) || ( ( attr . type === 'nv-attribute' || attr . type === 'directive' ) && oldVnodeAttr . nvValue !== attr . nvValue ) || ( attr . type === 'prop' && ! utils . isEqual ( oldVnodeAttr . nvValue , attr . nvValue ) ) ) ) { patchList . push ( { type : 3 , originVnode : oldVnode , changedValue : oldVnodeAttr , attributeType : oldVnodeAttr . type , } ) ; patchList . push ( { type : 4 , originVnode : oldVnode , changedValue : attr , attributeType : attr . type , } ) ; } } ) ; } if ( oldVnode . attributes && oldVnode . attributes . length > 0 ) { oldVnode . attributes . forEach ( ( attr ) => { const newVnodeAttr = newVnode . attributes . find ( newAttr => newAttr . type === attr . type && newAttr . name === attr . name ) ; if ( ! newVnodeAttr ) { patchList . push ( { type : 3 , originVnode : oldVnode , changedValue : attr , attributeType : attr . type , } ) ; } } ) ; } } param { Vnode } oldVnode param { Vnode } newVnode param { IPatchList [ ] } patchList returns { void } function diffNodeValue ( oldVnode , newVnode , patchList ) { if ( oldVnode . type !== 'text' ) return ; if ( oldVnode . nodeValue !== newVnode . nodeValue ) { patchList . push ( { type : 5 , originVnode : oldVnode , changedValue : newVnode . nodeValue , } ) ; } } param { Vnode } newVnode param { Vnode } oldVnode param { IPatchList [ ] } patchList returns { void } function diffValue ( oldVnode , newVnode , patchList ) { if ( oldVnode . value !== newVnode . value ) { patchList . push ( { type : 6 , originVnode : oldVnode , changedValue : newVnode . value , } ) ; } } param { Vnode } newVnode param { Vnode } oldVnode param { IPatchList [ ] } patchList returns { void } function diffRepeatData ( oldVnode , newVnode , patchList ) { if ( ! oldVnode . repeatData && ! newVnode . repeatData ) return ; if ( ! oldVnode . repeatData || ! newVnode . repeatData ) { patchList . push ( { type : 7 , originVnode : oldVnode , changedValue : newVnode . repeatData , } ) ; return ; } let isEqual = true ; const oldDataKeys = Object . keys ( oldVnode . repeatData ) ; const newDataKeys = Object . keys ( newVnode . repeatData ) ; if ( oldDataKeys . length !== newDataKeys . length ) isEqual = false ; if ( newDataKeys . length === newDataKeys . length ) { oldDataKeys . forEach ( key => { if ( ! newVnode . repeatData . hasOwnProperty ( key ) || oldVnode . repeatData [ key ] !== newVnode . repeatData [ key ] ) isEqual = false ; } ) ; } if ( isEqual ) return ; patchList . push ( { type : 7 , originVnode : oldVnode , changedValue : newVnode . repeatData , } ) ; } param { Vnode } oldVnode param { Vnode } newVnode param { IPatchList [ ] } patchList function diffEventTypes ( oldVnode , newVnode , patchList ) { const oEventTypes = oldVnode . eventTypes ; const nEventTypes = newVnode . eventTypes ; if ( oEventTypes && oEventTypes . length > 0 ) { oEventTypes . forEach ( oEventType => { if ( ! nEventTypes || nEventTypes . length <= 0 ) { patchList . push ( { type : 8 , originVnode : oldVnode , changedValue : oEventType , } ) ; } if ( nEventTypes && nEventTypes . length > 0 && ! nEventTypes . find ( nEventType => nEventType . type === oEventType . type ) ) { patchList . push ( { type : 8 , originVnode : oldVnode , changedValue : oEventType , } ) ; } } ) ; } if ( nEventTypes && nEventTypes . length > 0 ) { nEventTypes . forEach ( nEventType => { if ( ! oEventTypes || oEventTypes . length <= 0 ) { patchList . push ( { type : 9 , originVnode : oldVnode , changedValue : nEventType , } ) ; } if ( oEventTypes && oEventTypes . length > 0 ) { const sameEventType = oEventTypes . find ( oEventType => oEventType . type === nEventType . type ) ; if ( ! sameEventType ) { patchList . push ( { type : 9 , originVnode : oldVnode , changedValue : nEventType , } ) ; } if ( sameEventType && sameEventType . token !== nEventType . token ) { patchList . push ( { type : 8 , originVnode : oldVnode , changedValue : sameEventType , } ) ; patchList . push ( { type : 9 , originVnode : oldVnode , changedValue : nEventType , } ) ; } } } ) ; } } param { Vnode } oldVnode param { Vnode } newVnode param { IPatchList [ ] } patchList param { ( oldVnode : Vnode , newVnode : Vnode ) => boolean } needDiffChildCallback returns { void } export function diffVnode ( oldVnode , newVnode , patchList ) { if ( ! patchList ) throw new Error ( 'patchList can not be null, diffVnode must need an Array' ) ; if ( ! newVnode . parentVnode && ! newVnode . template && ! newVnode . tagName ) { diffChildNodes ( oldVnode , newVnode , patchList ) ; return ; } diffAttributes ( oldVnode , newVnode , patchList ) ; diffNodeValue ( oldVnode , newVnode , patchList ) ; diffValue ( oldVnode , newVnode , patchList ) ; diffRepeatData ( oldVnode , newVnode , patchList ) ; diffEventTypes ( oldVnode , newVnode , patchList ) ; diffChildNodes ( oldVnode , newVnode , patchList ) ; }