欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

微信小程序轉(zhuǎn)換器(一)—— 轉(zhuǎn)換器的實(shí)現(xiàn) - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們在追求其視覺表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏壧峁┍憬莸闹С郑?

您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

微信小程序轉(zhuǎn)換器(一)—— 轉(zhuǎn)換器的實(shí)現(xiàn)

發(fā)表時(shí)間:2021-1-5

發(fā)布人:葵宇科技

瀏覽次數(shù):72

準(zhǔn)備

在開始前得先準(zhǔn)備點(diǎn)東西:

  • 1、隨便學(xué)點(diǎn)node的api知識,用來操作文件
  • 2、AST Explorer一個(gè)可以看到各種插件轉(zhuǎn)出的AST樹結(jié)構(gòu)的網(wǎng)站
  • 3、JS的轉(zhuǎn)換器:@babel/parser(code -> AST)、@babel/traverse(用來遍歷得到的AST)、@babel/generator(AST -> code)
  • 4、HTML的轉(zhuǎn)換器 htmlparser2(HTML -> AST), AST -> HTML 的則需要自己手寫
  • 5、CSS的轉(zhuǎn)換器 css-tree 這一個(gè)干完所有

工具準(zhǔn)備

配置文件

需要個(gè)配置文件來標(biāo)明編譯入口

// analyze.config.js
const config = {
    entry: './',
    output: {
        name: 'dist',
        src: './'
    }
}
module.exports = config
復(fù)制代碼

封裝工具方法

// common.js
const path = require("path");
const fs = require("fs");
const config = require(path.resolve('./analyze.config.js'))

// 讀文件
function readFile(url) { 
    return fs.readFileSync(url, 'utf8')
}

// 寫文件
function writeFile(filename, data) { 
    return fs.writeFileSync(filename, data, 'utf8')
}

// 遞歸刪除文件夾
function deleteall(path) { 
	var files = [];
	if(fs.existsSync(path)) {
		files = fs.readdirSync(path);
		files.forEach(function(file, index) {
			var curPath = path + "/" + file;
			if(fs.statSync(curPath).isDirectory()) { // recurse
				deleteall(curPath);
			} else { // delete file
				fs.unlinkSync(curPath);
			}
		});
		fs.rmdirSync(path);
	}
}

// 復(fù)制文件
function copyFile(src, dist) { 
    fs.writeFileSync(dist, fs.readFileSync(src));
}

// 替換屬性
function replaceAtrr(option, key, aimsKey) {
    const value = http://www.wxapp-union.com/option[key]
    option[aimsKey] = value
    delete option[key]
}

// 獲得輸入路徑
function inputAppPath(url) {
    return url ? path.resolve(config.entry, url) : path.resolve(config.entry)
}

// 獲得輸出路徑
function outputAppPath(url) {
    return url ? path.resolve(config.output.src, config.output.name, url) : path.resolve(config.output.src, config.output.name)

}

復(fù)制代碼

封裝json替換映射表

主要是app.json中的window屬性、tabbar屬性需要替換。window屬性在頁面的json里也需要用到。

// compares.js
const WINDOWCONVERTERCONFIG = {
    'navigationBarTitleText':{ target: 'defaultTitle' },
    'enablePullDownRefresh':{ target: 'pullRefresh', 
        handler: (config) => { 
            const enablePullDownRefresh = config['enablePullDownRefresh']
            if (enablePullDownRefresh) config['allowsBounceVertical'] = 'YES'
        }
    },
    'navigationBarTitleText':{ target: 'defaultTitle' },
    'navigationStyle': {
        handler: (config) => {
            if (config['navigationStyle'] == 'custom') {
                config['transparentTitle'] == 'always'
                delete config['navigationStyle']
            }
        }
    }, 
    'navigationBarBackgroundColor':{ target: 'titleBarColor' },
    'onReachBottomDistance':{ target: 'onReachBottomDistance' },
}

const TABBARCONVERTERCONFIG = [
    { originalKey: 'color', key: 'textColor' },
    { originalKey: 'list', key: 'items' , list: [
        { originalKey: 'text', key: 'name' },
        { originalKey: 'iconPath', key: 'icon' },
        { originalKey: 'selectedIconPath', key: 'activeIcon' },
    ]},
]

module.exports = {
    WINDOWCONVERTERCONFIG,
    TABBARCONVERTERCONFIG
}

復(fù)制代碼

編譯文件

編譯入口

根據(jù)不同類型文件,選擇不同類型入口,將入口和源碼處理分開來,方便之后類似loader處理的拓展。之后編譯部分只用關(guān)心輸入的源碼和輸出的代碼就可以了。

// analyze.js

// Js編譯入口
function buildJs(inputPath, outputPath) {
    let source = readFile(inputPath)
    source = parseJS(source)
    writeFile(outputAppPath(outputPath), source)
    return source
}

// Json編譯入口
function buildJson(inputPath, outputPath) {
    let source = readFile(inputPath)
    
    const jonParser = new JsonParser()
    source = jonParser.parser(JSON.parse(source))
    source = JSON.stringify(source)
    
    writeFile(outputAppPath(outputPath), source)
    return source
}

// Html編譯入口
function buildXml(inputPath, outputPath) {
    let source = readFile(inputPath)

    parseXML(source).then(code => {
        writeFile(outputAppPath(outputPath), code)
    })
}

// Wxss編譯入口
function buildWxss(inputPath, outputPath) {
    let source = readFile(inputPath)
    
    const code = parseCSS(source)
    
    writeFile(outputAppPath(outputPath), code)
}

復(fù)制代碼

使用轉(zhuǎn)換器

function parseJS(source) {
    const jsParser = new JsParser()
    let ast = jsParser.parse(source)
    ast = jsParser.astConverter(ast)
    return jsParser.astToCode(ast)
}

async function parseXML(source) {
    const templateParser = new TemplateParser()
    let ast = await templateParser.parse(source)
    ast = templateParser.templateConverter(ast)
    return templateParser.astToString(ast)
}

function parseCSS(source) {
    const cssParser = new CssParser()
    let ast = cssParser.parse(source)
    ast = cssParser.astConverter(ast)
    return cssParser.astToCss(ast)
}
復(fù)制代碼

實(shí)現(xiàn)轉(zhuǎn)換器

js轉(zhuǎn)換器封裝

// JsParser.js js轉(zhuǎn)換器
const parser = require('@babel/parser')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default

class JsParser{
    constructor() {}

    // code -> ast
    parse(source) {
        let ast = parser.parse(source, {
            sourceType: 'module'
        })
        return ast
    }
    
    // ast 語法樹編輯
    astConverter(ast) {
        traverse(ast, {
            MemberExpression(p) {
                let node = p.node
                 // 遍歷wx方法調(diào)用的節(jié)點(diǎn),并將其替換成my調(diào)用
                if (node.object.name == 'wx') {
                    node.object.name = 'my'
                }
            }
        })
        return ast
    }

    // ast -> code
    astToCode(ast) {
        return generate(ast).code
    }
}
復(fù)制代碼

css轉(zhuǎn)換器封裝

// CssParser.js css轉(zhuǎn)換器
const csstree = require('css-tree')

class CssParser {
    constructor() {}

    // code -> ast
    parse(source) {
        const ast = csstree.parse(source)
        return ast
    }

    // ast 語法樹編輯
    astConverter(ast) {
        csstree.walk(ast, function(node) {
            if (node.type == 'Atrule' && node.name == 'import') {
                node.prelude.children.forEach(item => {
                    const value = http://www.wxapp-union.com/item.value
                    item.value = value.replace('.wxss','.acss')
                });              
            }
        })
        return ast
    }
    
    // ast -> code
    astToCss(ast) {
        return csstree.generate(ast)
    }
}
復(fù)制代碼

json轉(zhuǎn)換器封裝

// JsonParser.js json轉(zhuǎn)換器
const { WINDOWCONVERTERCONFIG } = require('./compares')

class JsonParser{
    constructor() {}
    
    // 替換屬性key
    parser(source) {
        function replaceAtrr(orginKey, key) {
            const value = http://www.wxapp-union.com/source[orginKey]
            source[key] = value
            delete source[orginKey]
        }

        Object.keys(source).forEach(key => {
            const item = WINDOWCONVERTERCONFIG[key]
            if (item) {
                if (item.target) replaceAtrr(key, item.target)
                item.handler && item.handler(source)
            }  
        })

        return source
    }

}

復(fù)制代碼

html轉(zhuǎn)換器封裝

html編譯器比較復(fù)雜,因?yàn)樗霓D(zhuǎn)換庫沒有提供AST轉(zhuǎn)換HTML的功能,需要自己去實(shí)現(xiàn)一下。需要替換的參照表也比較復(fù)雜。使用方法參考了這篇

// HtmlTemplateParser.js html轉(zhuǎn)換器
const htmlparser = require('htmlparser2')   //html的AST類庫

const ATTRCONVERTERCONFIG = {
    'wx:for':{ target:'a:for', },
    'wx:if':{ target: 'a:if' },
    'wx:elif':{ target: 'a:elif' },
    'else':{ target: 'a:else' },
    'wx:else':{ target: 'a:else' },
    'wx:for-index':{ target: 'a:for-index' },
    'wx:for-item':{ target: 'a:for-item' },
    'wx:key':{ target: 'a:key' },
    'bindtap':{ target: 'onTap' },
    'bindtouchstart':{ target: 'onTouchstart' },
    'bindtouchmove':{ target: 'onTouchMove' },
    'bindtouchend':{ target: 'onTouchEnd' },
    'bindtouchcancel':{ target: 'onTouchCancel' },
    'bindlongtap':{ target: 'onLongTap' },
    'bindlongpress':{ target: 'onLongTap' },
    'catchtap':{ target: 'catchTap' },
    'catchtouchstart':{ target: 'catchTouchstart' },
    'catchtouchmove':{ target: 'catchTouchMove' },
    'catchtouchend':{ target: 'catchTouchEnd' },
    'catchtouchcancel':{ target: 'catchTouchCancel' },
    'catchlongtap':{ target: 'catchLongTap' },
    'catchlongpress':{ target: 'catchLongTap' },
}

function comparesAtrr(attr, key) {
    function replaceAtrr(orginKey, key) {
        const value = http://www.wxapp-union.com/attr[orginKey]
        attr[key] = value
        delete attr[orginKey]
    }

    if (ATTRCONVERTERCONFIG[key]) replaceAtrr(key, ATTRCONVERTERCONFIG[key].target)
}

class TemplateParser{
    constructor() {}
	
    // code -> ast
    parse(source){
        return new Promise((resolve, reject) => {
            const handler = new htmlparser.DomHandler((error, dom)=>{
                if (error) reject(error);
                else resolve(dom);
            });
            let parser = new htmlparser.Parser(handler)
            parser.write(source)
            parser.end()
        })
    }
        
    // ast -> code
    astToString (ast) {
        let str = '';
            ast.forEach(item => {
                if (item.type === 'text') {
                str += item.data;
                } else if (item.type === 'tag') {
                str += '<' + item.name;
                if (item.attribs) {
                    Object.keys(item.attribs).forEach(attr => {
                    str += ` ${attr}="${item.attribs[attr]}"`;
                    });
                }
                str += '>';
                if (item.children && item.children.length) {
                    str += this.astToString(item.children);
                }
                str += `${item.name}>`;
                }
            });
        return str;
    }
   
    // ast 語法樹編輯
    templateConverter(ast){
        for(let i = 0;i){
          let node = ast[i]
          //檢測到是html節(jié)點(diǎn)
          if(node.type === 'tag'){
            // 遍歷節(jié)點(diǎn)屬性,對比參照表有沒有需要替換的部分
            Object.keys(node.attribs).forEach(key => {
                comparesAtrr(node.attribs, key)
            })
          }
          //因?yàn)槭菢錉罱Y(jié)構(gòu),所以需要進(jìn)行遞歸
          if(node.children) this.templateConverter(node.children)
        }
        return ast
    }

}

復(fù)制代碼
我對跨小程序想說的話和看法

先說一下我對這個(gè)事的看法,市面上有antmove已經(jīng)做到這個(gè)事了,但總的來說差異都不可能完全磨平,只能說是同樣小程序平臺轉(zhuǎn)換上需要更改的成本會比較低。然后我覺得運(yùn)行時(shí)每套方法寫一遍來區(qū)別不同平臺的方案,可能需要同時(shí)適應(yīng)n套混雜規(guī)則,當(dāng)有問題了,不知道該去遵守哪一套規(guī)則,開發(fā)體驗(yàn)可能不是特別好。因此我更偏向于靠編譯的方式來大概磨平差異,后續(xù)迭代也可以選擇只編譯更新了的部分內(nèi)容。 以上純屬本人愚見。請不要太在意。

相關(guān)案例查看更多