微信小程序 使用 SVG

将 svg 转成 base64 后使用

如在 https://loading.io/ 右键打开图片 

https://loading.io/spinners/lava-lamp/index.svg

右键保存本地

将 svg 转换成 base64

https://www.sojson.com/image2base64.html

在小程序的 CSS 里使用 背景图片的方式调用 base64 后的 svg

或使用 image 标签

PHP 强制下载类 不使用浏览器预览图片、PDF 等

<?php
namespace download;
class ForceDownload
{
/**
* Force Download
*
* Generates headers that force a download to happen
*
* @param	string	filename
* @param	mixed	the data to be downloaded
* @param	bool	whether to try and send the actual file MIME type
* @return	void
*/
public function force_download($filename = '', $data = '', $set_mime = FALSE)
{
if ($filename === '' OR $data === '')
{
return;
}
elseif ($data === NULL)
{
if ( ! @is_file($filename) OR ($filesize = @filesize($filename)) === FALSE)
{
return;
}
$filepath = $filename;
$filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename));
$filename = end($filename);
}
else
{
$filesize = strlen($data);
}
// Set the default MIME type to send
$mime = 'application/octet-stream';
$x = explode('.', $filename);
$extension = end($x);
if ($set_mime === TRUE)
{
if (count($x) === 1 OR $extension === '')
{
/* If we're going to detect the MIME type,
* we'll need a file extension.
*/
return;
}
// Load the mime types
$mimes =& self::get_mimes();
// Only change the default MIME if we can find one
if (isset($mimes[$extension]))
{
$mime = is_array($mimes[$extension]) ? $mimes[$extension][0] : $mimes[$extension];
}
}
/* It was reported that browsers on Android 2.1 (and possibly older as well)
* need to have the filename extension upper-cased in order to be able to
* download it.
*
* Reference: http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
*/
if (count($x) !== 1 && isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Android\s(1|2\.[01])/', $_SERVER['HTTP_USER_AGENT']))
{
$x[count($x) - 1] = strtoupper($extension);
$filename = implode('.', $x);
}
if ($data === NULL && ($fp = @fopen($filepath, 'rb')) === FALSE)
{
return;
}
// Clean output buffer
if (ob_get_level() !== 0 && @ob_end_clean() === FALSE)
{
@ob_clean();
}
// Generate the server headers
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.$filesize);
header('Cache-Control: private, no-transform, no-store, must-revalidate');
// If we have raw data - just dump it
if ($data !== NULL)
{
exit($data);
}
// Flush 1MB chunks of data
while ( ! feof($fp) && ($data = fread($fp, 1048576)) !== FALSE)
{
echo $data;
}
fclose($fp);
exit;
}
public static function &get_mimes()
{
static $_mimes;
if (empty($_mimes))
{
$_mimes = array(
'hqx'	=>	array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
'cpt'	=>	'application/mac-compactpro',
'csv'	=>	array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'),
'bin'	=>	array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
'dms'	=>	'application/octet-stream',
'lha'	=>	'application/octet-stream',
'lzh'	=>	'application/octet-stream',
'exe'	=>	array('application/octet-stream', 'application/x-msdownload'),
'class'	=>	'application/octet-stream',
'psd'	=>	array('application/x-photoshop', 'image/vnd.adobe.photoshop'),
'so'	=>	'application/octet-stream',
'sea'	=>	'application/octet-stream',
'dll'	=>	'application/octet-stream',
'oda'	=>	'application/oda',
'pdf'	=>	array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'),
'ai'	=>	array('application/pdf', 'application/postscript'),
'eps'	=>	'application/postscript',
'ps'	=>	'application/postscript',
'smi'	=>	'application/smil',
'smil'	=>	'application/smil',
'mif'	=>	'application/vnd.mif',
'xls'	=>	array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'),
'ppt'	=>	array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'),
'pptx'	=> 	array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'),
'wbxml'	=>	'application/wbxml',
'wmlc'	=>	'application/wmlc',
'dcr'	=>	'application/x-director',
'dir'	=>	'application/x-director',
'dxr'	=>	'application/x-director',
'dvi'	=>	'application/x-dvi',
'gtar'	=>	'application/x-gtar',
'gz'	=>	'application/x-gzip',
'gzip'  =>	'application/x-gzip',
'php'	=>	array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'),
'php4'	=>	'application/x-httpd-php',
'php3'	=>	'application/x-httpd-php',
'phtml'	=>	'application/x-httpd-php',
'phps'	=>	'application/x-httpd-php-source',
'js'	=>	array('application/x-javascript', 'text/plain'),
'swf'	=>	'application/x-shockwave-flash',
'sit'	=>	'application/x-stuffit',
'tar'	=>	'application/x-tar',
'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
'z'	=>	'application/x-compress',
'xhtml'	=>	'application/xhtml+xml',
'xht'	=>	'application/xhtml+xml',
'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'),
'rar'	=>	array('application/x-rar', 'application/rar', 'application/x-rar-compressed'),
'mid'	=>	'audio/midi',
'midi'	=>	'audio/midi',
'mpga'	=>	'audio/mpeg',
'mp2'	=>	'audio/mpeg',
'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
'aif'	=>	array('audio/x-aiff', 'audio/aiff'),
'aiff'	=>	array('audio/x-aiff', 'audio/aiff'),
'aifc'	=>	'audio/x-aiff',
'ram'	=>	'audio/x-pn-realaudio',
'rm'	=>	'audio/x-pn-realaudio',
'rpm'	=>	'audio/x-pn-realaudio-plugin',
'ra'	=>	'audio/x-realaudio',
'rv'	=>	'video/vnd.rn-realvideo',
'wav'	=>	array('audio/x-wav', 'audio/wave', 'audio/wav'),
'bmp'	=>	array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'),
'gif'	=>	'image/gif',
'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
'jpe'	=>	array('image/jpeg', 'image/pjpeg'),
'png'	=>	array('image/png',  'image/x-png'),
'tiff'	=>	'image/tiff',
'tif'	=>	'image/tiff',
'css'	=>	array('text/css', 'text/plain'),
'html'	=>	array('text/html', 'text/plain'),
'htm'	=>	array('text/html', 'text/plain'),
'shtml'	=>	array('text/html', 'text/plain'),
'txt'	=>	'text/plain',
'text'	=>	'text/plain',
'log'	=>	array('text/plain', 'text/x-log'),
'rtx'	=>	'text/richtext',
'rtf'	=>	'text/rtf',
'xml'	=>	array('application/xml', 'text/xml', 'text/plain'),
'xsl'	=>	array('application/xml', 'text/xsl', 'text/xml'),
'mpeg'	=>	'video/mpeg',
'mpg'	=>	'video/mpeg',
'mpe'	=>	'video/mpeg',
'qt'	=>	'video/quicktime',
'mov'	=>	'video/quicktime',
'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
'movie'	=>	'video/x-sgi-movie',
'doc'	=>	array('application/msword', 'application/vnd.ms-office'),
'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'),
'dot'	=>	array('application/msword', 'application/vnd.ms-office'),
'dotx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'),
'word'	=>	array('application/msword', 'application/octet-stream'),
'xl'	=>	'application/excel',
'eml'	=>	'message/rfc822',
'json'  =>	array('application/json', 'text/json'),
'pem'   =>	array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
'p10'   =>	array('application/x-pkcs10', 'application/pkcs10'),
'p12'   =>	'application/x-pkcs12',
'p7a'   =>	'application/x-pkcs7-signature',
'p7c'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
'p7m'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
'p7r'   =>	'application/x-pkcs7-certreqresp',
'p7s'   =>	'application/pkcs7-signature',
'crt'   =>	array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
'crl'   =>	array('application/pkix-crl', 'application/pkcs-crl'),
'der'   =>	'application/x-x509-ca-cert',
'kdb'   =>	'application/octet-stream',
'pgp'   =>	'application/pgp',
'gpg'   =>	'application/gpg-keys',
'sst'   =>	'application/octet-stream',
'csr'   =>	'application/octet-stream',
'rsa'   =>	'application/x-pkcs7',
'cer'   =>	array('application/pkix-cert', 'application/x-x509-ca-cert'),
'3g2'   =>	'video/3gpp2',
'3gp'   =>	array('video/3gp', 'video/3gpp'),
'mp4'   =>	'video/mp4',
'm4a'   =>	'audio/x-m4a',
'f4v'   =>	'video/mp4',
'webm'	=>	'video/webm',
'aac'   =>	'audio/x-acc',
'm4u'   =>	'application/vnd.mpegurl',
'm3u'   =>	'text/plain',
'xspf'  =>	'application/xspf+xml',
'vlc'   =>	'application/videolan',
'wmv'   =>	array('video/x-ms-wmv', 'video/x-ms-asf'),
'au'    =>	'audio/x-au',
'ac3'   =>	'audio/ac3',
'flac'  =>	'audio/x-flac',
'ogg'   =>	'audio/ogg',
'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
'ics'	=>	'text/calendar',
'ical'	=>	'text/calendar',
'zsh'	=>	'text/x-scriptzsh',
'7zip'	=>	array('application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'),
'cdr'	=>	array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'),
'wma'	=>	array('audio/x-ms-wma', 'video/x-ms-asf'),
'jar'	=>	array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'),
'svg'	=>	array('image/svg+xml', 'application/xml', 'text/xml'),
'vcf'	=>	'text/x-vcard',
'srt'	=>	array('text/srt', 'text/plain'),
'vtt'	=>	array('text/vtt', 'text/plain'),
'ico'	=>	array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon')
);
}
return $_mimes;
}
}

调用

public function down(){
$down = new ForceDownload();
$down->force_download('uploads/xx.pdf',NULL,TRUE);
}

ThinkPHP 5 使用方法

放到 extend/download/ 文件夹下,即 extend/download/ForceDownload.php

实例化 $down = new \download\ForceDownload();

调用  $down->force_download('uploads/xx.pdf',NULL,TRUE);

微信小程序 消息模板 发送推送消息 快速测试 DEMO

首先 微信公众平台 后台添加模板消息

/utils/config.js

var config = {
APPID:'wxe1af000000000000',
APPSECRET:'050000000000000000000000000000',
TEMPLATE_ID:{
'msg': 'Y2idRTMVs4e_w72uSiPATptx3yFfIp2B97H8GXj_XXX'
}
}
module.exports = config

/utils/wxapi.js

注意:正式环境中不允许访问 api.weixin.qq.com , 仅在测试环境下测试并开启不校验合法域名

var config = require('config.js')
const access_token = function(callback = function() {}) {
wx.request({
method: 'GET',
url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + config.APPID + '&secret=' + config.APPSECRET,
data: {},
success: function(res) {
console.log(res)
callback(res)
}
})
}
const template = function(params={},callback=function(){}) {
var data = {
touser: params.openid,
template_id: config.TEMPLATE_ID.msg,
form_id: params.form_id,
data: {
"keyword1": {
"value": "测试文字,通过",
"color": "#4a4a4a"
},
"keyword2": {
"value": new Date(),
"color": "#9b9b9b"
}
},
color: 'red', //颜色
emphasis_keyword: 'keyword2.DATA' //需要着重显示的关键词
}
wx.request({
url: 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=' + params.access_token,
method: 'POST',
data: data,
success:function(res){
console.log(res)
callback(res)
}
})
}
const openid = function(callback=function(){}){
wx.login({
success: function (res) {
if (res.code) {
//发起网络请求 将code传给服务器
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session?appid='+config.APPID+'&secret='+config.APPSECRET+'&js_code='+res.code+'&grant_type=authorization_code',
data: {},
success:function(res){
console.log(res)
callback(res)
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
}
module.exports = {
access_token: access_token,
template: template,
openid: openid
}

/pages/test/test.js

const wxapi = require('../../utils/wxapi.js')
Page({
getFormID: function (e) {
var that = this
console.log(e)
console.log(e.detail.formId)
wx.showToast({
title: e.detail.formId,
icon:'none'
})
that.setData({
form_id: e.detail.formId
})
},
getAccessToken:function(){
var that = this
wxapi.access_token(function (res) {
wx.showToast({
title: res.data.access_token,
icon: 'none'
})
that.setData({
access_token: res.data.access_token
})
})
},
getOpenid:function(){
var that = this
wxapi.openid(function(res){
wx.showToast({
title: res.data.openid,
icon:'none'
})
that.setData({
openid:res.data.openid
})
})
},
sendTemplate: function () {
var data = {
'access_token': this.data.access_token,
'form_id': this.data.form_id,
'openid': this.data.openid,
}
wxapi.template(data, function (res) {
wx.showToast({
title: res.data.errmsg,
icon: 'none',
duration: 5000
})
})
},
})

/pages/test/test.wxml

<form name='pushMsgFm' report-submit='true' bindsubmit='getFormID'> 
<button size='mini' form-type="submit" class="zan-btn zan-btn--large zan-btn--danger payButton">获取 form_id</button>
</form>  
<button size='mini' bindtap='getAccessToken'>获取 access_token</button>
<button size='mini' bindtap='getOpenid'>获取 openid</button>
<button size='mini' bindtap='sendTemplate'>发送测试</button>

依次点击四个按钮即可测试

微信小程序 自带 GPS 定位的坑

微信小程序打卡定位调试了一天始终差五百多米。百度坐标转换各种问题都找了都没问题,最终发现是小程序自带定位有问题,文档里也没有写,大坑。

const getLocation = function(callback = function() {}) {
wx.getLocation({
type: 'GCJ02',
success: function(res) {
console.log('微信自带定位返回结果')
console.log(res)
wx.setClipboardData({
data: JSON.stringify({ 'lat': lat, 'lng': lng }),
})
callback(res)
}
}) 
}
const getLocation = function(callback = function() {}) {
wx.getLocation({
type: 'gcj02',
success: function(res) {
console.log('微信自带定位返回结果')
console.log(res)
wx.setClipboardData({
data: JSON.stringify({ 'lat': lat, 'lng': lng }),
})
callback(res)
}
}) 
}

大写的 GCJ02 便宜了五百多米, 小写的 gcj02 是正确的

小程序自带的 map 组件不受此影响,但就是因为不受影响我一直以为不是微信的问题。

卧了个大凸(艹皿艹 )

微信小程序 BASE64 encode 加密 decode 解密

utils/base64.js

var Base64 = {
// private property
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode: function(input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode: function(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode: function(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode: function(utftext) {
var string = "";
var i = 0;
var c = 0;
var c1 = 0;
var c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
module.exports = Base64

使用 引包

const base64 = require('base64.js')

微信小程序 封装 httpPost 方法 发送 PHPSESSID 保持登录连接

utils/config.js

var config = {
APPID:'wxe1af0e00000000f3',
BASE_URL:'https://xx.xxx.xx/xx/',
}
module.exports = config

utils/util.js 文件

var config = require('config.js')
function Post(url, data, cb,header=null) {
if(header = 'session'){
var headerObj = {
'content-type': 'application/x-www-form-urlencoded',
'Cookie': 'PHPSESSID=' + wx.getStorageSync('sessionid')
}
}else{
var headerObj = {
'content-type': 'application/x-www-form-urlencoded'
}
}
wx.request({
method: 'POST',
url: config.BASE_URL + url,
data: data,
header: headerObj,
success: (res) => {
console.log("post 请求:" + config.BASE_URL + url);
console.log(res.data)
typeof cb == "function" && cb(res.data, "");
},
fail: (err) => {
typeof cb == "function" && cb(null, err.errMsg)
console.log("post 请求:" + config.BASE_URL + url);
console.log(err);
}
})
} 
module.exports = {
httpPost: Post,
}

使用 如 /pages/index.js

const util = require('../../utils/util.js')
test: function() {
util.httpPost('index.php?s=/sign/gettimeplan',{'userid':805},function(res){
console.log(res.result[0])
},'session')
}

Swoole 绑定域名 80 端口 (Nginx 监听转发)

启动 Swoole 的 http server,可以使用 IP + 端口 进行访问

创建 Nginx 虚拟域名

vim swotp.liuguofeng.com.conf
server
{
listen 80;
server_name swotp.liuguofeng.com ;
index index.html index.htm index.php default.html default.htm default.php;
root  /home/wwwroot/swoole_thinkphp.liuguofeng.com;
location / {
if (!-e $request_filename) {
proxy_pass http://127.0.0.1:8811;
}
}
}

重启 Nginx,DNS 指向 IP 

微信小程序 使用自带 rich-text 组件进行 HTML 富文本解析

JS

Page({
/**
* 页面的初始数据
*/
data: {
html: '<div class="div_class" style="line-height: 60px; color: red;">Hello World!</div><img src="/resource/test/test.jpg" style="width:200px;height:200px;"/>',    
},
})

WXML

<rich-text nodes="{{html}}" data-data="{{html}}" bindtap="tap"></rich-text>

开发文档:

https://developers.weixin.qq.com/miniprogram/dev/component/rich-text.html

微信小程序 使用 wxParse HTML 富文本解析

下载地址 https://github.com/icindy/wxParse

将 wxParse 拷贝到项目目录下,本人拷至 /utils下,见引用

JS

const WxParse = require('../../utils/wxParse/wxParse.js')
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.htmlTest()    
},
htmlTest:function(){
var article = "<div>我是HTML代码</div><img src='/resource/test/test.jpg'/>"
var that = this
WxParse.wxParse('article', 'html', article, that, 5)
},
})

WXML

<import src='../../utils/wxParse/wxParse.wxml' />
<template is="wxParse" data="{{wxParseData:article.nodes}}" />

WXSS

@import "/utils/wxParse/wxParse.wxss";