zoukankan      html  css  js  c++  java
  • 虚拟dom节点,支持querySelector

    虚拟dom节点,支持querySelector,

    方法:

    hasQuerySelector 输入css选择器,判断是否选中dom
    querySelectorToHtml 输入css选择器,输出命中的html
    querySelector 输入css选择器,输出bitmap数据


    HtmlNode.js
    //HtmlNode.js
    const Api=require('./Api');
    const compiler = require('vue-template-compiler');
    
    //命中规则
    /*css rule矩阵,
    行对应selector '.id',
    列对应html节点 ['body','body div','body div div','body div p','body div span','body div span a']
    [
        [0,0,0,0,1,0],
    ]
    */
    class HtmlNode{
    
        constructor(htmlText){
            let htmlAst=htmlText==='string'?compiler.compile(htmlText).ast:htmlText;
    
            //记录selector查找历史
            this.selectotCache={};
    
            //构建html语法树和矩阵bitmap
            this.htmlAst=htmlAst;
            this.htmlList=this.getAllChild(this.htmlAst);
        }
    
        //选择器是否命中dom节点
        hasQuerySelector(selector){
            return this.querySelector(selector).some(function (item) {
                return item===1
            })
        }
        //根据selector获取html文本
        querySelectorToHtml(selector){
            const selectorArr=this.querySelector(selector);
            let html='';
            for(let i=0;i<selectorArr.length;i++){
                if(selectorArr[i]===1){
                    html+=Api.AstToHtml(this.htmlList[i])
                }
            }
            return html;
        }
        //获取选择器和它得子元素
        queryAllSelector(selector){
            const arr=this.querySelector(selector);
            for(let i=0;i<arr.length;i++){
                if(arr[i]===1){
                    const cLen=this.getAllChild(this.htmlList[arr[i]]).length;
                    for(let k=1;k<cLen;k++){
                        i++;
                        arr[i]=1;
                    }
                }
            }
            return arr;
        }
        //递归获取所有当前元素、子元素
        getAllChild(nodeAst){
            return Api.depthSearch(nodeAst).filter(function (node) {
                return node.type===1;
            })
        }
        //可能是多选择器
        querySelector(selector){
            if(/,/.test(selector)){
                const arr=selector.split(',');
                const data=[];
                for(let i=0;i<arr.length;i++){
                    const item=this.queryOneSelector(arr[i]);
                    for(let k=0;k<item.length;k++){
                        if(item[k]===1){
                            data[k]=1;
                        }else{
                            data[k]=0;
                        }
                    }
                }
                return data;
            }else{
                return this.queryOneSelector(selector)
            }
        }
        //查询css_rule,返回[array astNode]
        queryOneSelector(selector){
            selector=selector.trim();//去掉左右空格
    
            //解析css rule
            const selectorArr=[]
            selector.replace(/(.+?)([ >~+]+(?!d)(?! *:)|$)/ig,function (m,p1,p2) {
                selectorArr.push(p1,p2);
            })
            // console.log(selectorArr)
            this.selectorArr=selectorArr;
            // console.log(selectorArr)
            //设置缓存
    
            let preSelector='';
            for(let i=0;i<selectorArr.length;i=i+2){
                const exec=selectorArr[i-1]||'';
                const curSelector=selectorArr[i];
    
                this.setSelectotCache(preSelector,exec,curSelector);
                preSelector=preSelector+exec+curSelector
            }
            const arr=new Array(this.htmlList.length).fill(0);
            // if(/ ::/.test(selector))
            // console.log(selector,selectorArr)
            this.selectotCache[selector].forEach( (node) =>{
                arr[this.htmlList.indexOf(node)]=1;
            })
            return arr;
        }
        //记录selector查询html语法树
        setSelectotCache(preSelector,exec,curSelector){
    
            const nextSelector=preSelector+exec+curSelector;
            //已有缓存
            if(this.selectotCache[nextSelector]){return;}
            if(!preSelector&&!exec){
                this.selectotCache[curSelector]=this.breadthHit(curSelector,this.htmlAst)
                return;
            }
            const arr=this.selectotCache[preSelector];
    
            this.selectotCache[nextSelector]=[];
            if(/^ +$/.test(exec)){
                arr.forEach((node)=>{
                    this.selectotCache[nextSelector]=this.selectotCache[nextSelector].concat(this.breadthHit(curSelector,node));
                })
            }else if(/^ *> *$/.test(exec)){
                arr.forEach((node)=>{
                    this.selectotCache[nextSelector]=this.selectotCache[nextSelector].concat(this.childHit(curSelector,node));
                })
            }else if(/^ *+ *$/.test(exec)){
                arr.forEach((node)=>{
                    this.selectotCache[nextSelector]=this.selectotCache[nextSelector].concat(this.sublingHit(curSelector,node));
                })
            }else if(/^ *~ *$/.test(exec)){
                arr.forEach((node)=>{
                    this.selectotCache[nextSelector]=this.selectotCache[nextSelector].concat(this.sublingsHit(curSelector,node));
                })
            }else{
                console.log('exec异常:'+exec)
            }
    
        }
        //css_rule:element+element
        sublingHit(tag,astNode){
            if(!astNode.parent){
                return [astNode].filter( (node) =>{
                    return this.hitNode(tag,node);
                })
            }
            return Api.nextSublingSearch(astNode,astNode.parent).filter( (node) =>{
                return this.hitNode(tag,node);
            })
        }
        //css_rule:element~element
        sublingsHit(tag,astNode){
            return Api.nextSublingsSearch(astNode,astNode.parent).filter(function (node) {
                return this.hitNode(tag,node);
            })
        }
        //css_rule:element element
        breadthHit(tag,astNode){
            return Api.breadthSearch(astNode).filter( (node)=> {
                return node.type===1&&this.hitNode(tag,node);
            })
        }
        //css_rule:element>element
        childHit(tag,astNode){
            return Api.childSearch(astNode).filter( (node)=> {
                return node.type===1&&this.hitNode(tag,node);
            })
        }
        //tag是否命中ast节点,返回true、false
        hitNode(selector,astNode) {
    
            //分割字符串 (tag)、(id、class)(val)
            if(selector==='*'){
                return true;
            }else if(/:root/.test(selector)){
                return astNode.tag==='html';
            }else{
                const arr=[];
                //tag
                if(/(^[a-z]+)/i.test(selector)){
                    const tag=RegExp.$1;
                    arr.push(astNode.tag===tag)
                }
                //class
                if(/.([w-]+)/.test(selector)){
                    const val=RegExp.$1;
                    arr.push(astNode.attrsMap.class&&astNode.attrsMap.class.split(' ').indexOf(val)>-1);
                }
                //id
                if(/#(w+)/.test(selector)){
                    const val=RegExp.$1;
                    arr.push(astNode.attrsMap.id===val);
                }
                //属性
                if(/[([w-]+)(~=|=||=)?(w+)?]/.test(selector)){
                    const key=RegExp.$1;
                    const exec=RegExp.$2;
                    const val=RegExp.$3;
                    // console.log(selector,'属性选择器,只判断是否存在属性')
                    arr.push(astNode.attrsMap.hasOwnProperty(key));
                }
                //伪类选择器
                if(/(:.+)/.test(selector)){
                    const key=RegExp.$1;
                    // console.log(selector,'解析->',selector.replace(/:.+$/,''))
                    arr.push(true)
                    // arr.push(astNode.attrsMap.id===val);
                }
                if(arr.length==0){
                    // console.log(this.selectorArr)
                    console.log(selector,this.selectorArr,'css 解析异常')
                }
                return arr.every((item)=>item);
            }
    
    
    
        }
    }
    module.exports=HtmlNode;

    Api.js

    //Api.js
    const treeSearch=require('./treeSearch');
    const AstToHtml = require("./AstToHtml");
    //遍历子节点
    function childSearch(node,childProp='children'){
        return node[childProp];
    }
    //遍历兄弟节点
    function nextSublingsSearch(node,pnode,childProp='children'){
        const parr=pnode[childProp].filter((node)=>{
            return node.type===1
        });
        return parr.slice(parr.indexOf(node)+1);
    }
    //遍历下一个兄弟节点
    function nextSublingSearch(node,pnode,childProp='children'){
        return nextSublingsSearch(node,pnode).slice(0,1);
    }
    module.exports={
        AstToHtml,
        childSearch,
        nextSublingsSearch,
        nextSublingSearch,
        ...treeSearch
    }

    AstToHtml.js

    //html语法树节点类型
    const typeMap= {
        '1':function (node) {
            if(node.attrs&&node.attrs.length>0){
                node.attrs.forEach(function (item) {
                    item.type='attrs'
                })
            }
            return [
                '<',
                node.tag,
                node.staticClass?[' class=',node.staticClass]:'',
                node.attrs&&node.attrs.length>0?[' ',joinSymbol(node.attrs,' ')]:'',
                '>',
                node.children,
                '</',
                node.tag,
                '>',
            ];
        },
        attrs:function (node) {
            return [node.name,'=',node.value]
        },
        '3':function (node) {
            return node.text;
        },
    }
    //语法树转string
    function AstChildToString(children) {
        let str='';
        children.forEach(function (node) {
            str+=AstToHtml(node)
        })
        return str;
    }
    //元素之间添加符号
    function joinSymbol(oriArr,symbol,pre) {
        if(oriArr.length===0){return '';}
        const arr=[];
        if(pre){
            arr.push(pre)
        }
        oriArr.forEach(function (node,i) {
            arr.push(node);
            if(i<oriArr.length-1){
                arr.push(symbol);
            }
        })
        if(pre){
            arr.push(pre)
        }
        return arr;
    }
    //语法树转string
    function AstToHtml(ast){
        if(Object.prototype.toString.call(ast)==='[object Array]'){
            return AstChildToString(ast);
        }else if(Object.prototype.toString.call(ast)==='[object String]'){
            return ast;
        }else if(ast===null){
            return '';
        }
        let code=typeMap[ast.type](ast);
    
        if(Object.prototype.toString.call(code)==='[object Array]'){
            const arr=code.map(function(obj){
                if(Object.prototype.toString.call(obj)==='[object Object]'){
                    return AstToHtml(obj);
                }else if(Object.prototype.toString.call(obj)==='[object Array]'){
                    return AstToHtml(obj);
                }
                return obj;
            })
            return arr.join('');
        }else{
            return code;
        }
    
    }
    module.exports=AstToHtml;

    treeSearch.js

    //treeSearch.js
    //广度遍历html节点
    function breadthSearch(item, childProp='children'){
        const nodeList=[item]
        let index=0;
        while (index<nodeList.length){
            const node=nodeList[index++];
            if(node[childProp]){
                for(let k in node[childProp]){
                    nodeList.push(node[childProp][k]);
                }
            }
        }
        return nodeList;
    }
    //深度遍历html节点
    function depthSearch(node,childProp='children'){
        const nodeList=[]
        const depthEach=function(item){
            nodeList.push(item);
            if(item[childProp]){
                for(let k in item[childProp]){
                    depthEach(item[childProp][k]);
                }
            }
        }
        depthEach(node);
        return nodeList;
    }
    
    module.exports={
        breadthSearch,depthSearch
    }
  • 相关阅读:
    美化博客园
    ansible的安装
    面向对象和类
    函数知识分类
    生成器
    内置函数_old
    迭代器
    装饰器
    Hadoop——MapReduce
    Hadoop——HDFS
  • 原文地址:https://www.cnblogs.com/caoke/p/11314569.html
Copyright © 2011-2022 走看看