diff --git a/androidPrivacy.json b/androidPrivacy.json
new file mode 100644
index 00000000..0d726ca9
--- /dev/null
+++ b/androidPrivacy.json
@@ -0,0 +1,3 @@
+{
+ "prompt" : "template"
+}
diff --git a/components/vlog/videoComp.vue b/components/vlog/videoComp.vue
new file mode 100644
index 00000000..1d14d2ab
--- /dev/null
+++ b/components/vlog/videoComp.vue
@@ -0,0 +1,740 @@
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+ @{{ item.vlogerName }}
+ {{ item.content }}
+
+
+ {{ item.vlogerName }}的原声创作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ getGraceNumber(item.likeCounts) }}
+
+
+
+
+
+
+ {{ getGraceNumber(thisVlogTotalComentCounts) }}
+
+
+
+
+ 分享
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/vlog/videoDetail.vue b/components/vlog/videoDetail.vue
new file mode 100644
index 00000000..cecdab93
--- /dev/null
+++ b/components/vlog/videoDetail.vue
@@ -0,0 +1,646 @@
+
+
+
+ |
+
+
+
+
+ @{{ item.vlogerName }}
+ {{ item.content }}
+
+
+ {{ item.vlogerName }}的原声创作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.likeCounts }}
+
+
+
+ {{ thisVlogTotalComentCounts }}
+
+
+
+ 分享
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/vlog/videoFollowComp.vue b/components/vlog/videoFollowComp.vue
new file mode 100644
index 00000000..5980b393
--- /dev/null
+++ b/components/vlog/videoFollowComp.vue
@@ -0,0 +1,739 @@
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ 关注列表为空
+
+ |
+
+
+
+
+
+
+
+ @{{item.vlogerName}}
+ {{item.content}}
+
+
+ {{item.vlogerName}}的原声创作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.likeCounts}}
+
+
+
+
+ {{thisVlogTotalComentCounts}}
+
+
+
+ 分享
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/me/chooseCity.nvue b/pages/me/chooseCity.nvue
new file mode 100644
index 00000000..ddb97d0e
--- /dev/null
+++ b/pages/me/chooseCity.nvue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+ {{ item.city_name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/me/chooseDistrict.nvue b/pages/me/chooseDistrict.nvue
new file mode 100644
index 00000000..2ed43370
--- /dev/null
+++ b/pages/me/chooseDistrict.nvue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+ {{ item.district_name }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/me/chooseProvince.nvue b/pages/me/chooseProvince.nvue
new file mode 100644
index 00000000..ed7d9b57
--- /dev/null
+++ b/pages/me/chooseProvince.nvue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+ {{ item.province_name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/me/modifyBirthday.vue b/pages/me/modifyBirthday.vue
new file mode 100644
index 00000000..e53ea41b
--- /dev/null
+++ b/pages/me/modifyBirthday.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+ {{ date }}
+
+
+
+
+
+
+
+
+ *注:点击即可选择生日噢~
+
+
+
+
+
+
+
diff --git a/pages/me/modifyDesc.vue b/pages/me/modifyDesc.vue
new file mode 100644
index 00000000..6b1c7245
--- /dev/null
+++ b/pages/me/modifyDesc.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+ {{ wordsLength }}/16
+
+
+
+
+ *注:请设置0-16字的个人简介
+
+
+
+
+
+
+
diff --git a/pages/me/modifyLocation.vue b/pages/me/modifyLocation.vue
new file mode 100644
index 00000000..8f49a6b4
--- /dev/null
+++ b/pages/me/modifyLocation.vue
@@ -0,0 +1,196 @@
+
+
+
+
+ 中国
+
+
+ {{ areaText }}
+
+
+
+
+
+ *注:点击即可选择省份与城市~
+
+
+
+
+
+
+
diff --git a/pages/me/modifyNickname.vue b/pages/me/modifyNickname.vue
new file mode 100644
index 00000000..4dffd1fe
--- /dev/null
+++ b/pages/me/modifyNickname.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+ {{ wordsLength }}/16
+
+
+
+
+ *注:请设置5-16的昵称长度
+
+
+
+
+
+
+
diff --git a/pages/me/modifySex.vue b/pages/me/modifySex.vue
new file mode 100644
index 00000000..3fdc5a82
--- /dev/null
+++ b/pages/me/modifySex.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+ 男
+
+
+
+
+
+
+
+
+ 女
+
+
+
+
+
+
+
+
+ 保密
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/me/modifyTioktokNum.vue b/pages/me/modifyTioktokNum.vue
new file mode 100644
index 00000000..06972fd0
--- /dev/null
+++ b/pages/me/modifyTioktokNum.vue
@@ -0,0 +1,221 @@
+
+
+
+
+ 👉🏻 修改次数已达上限!
+
+
+
+
+ {{ wordsLength }}/16
+
+
+
+
+ *注:请设置5-16的视频号长度,视频号只能修改一次噢~!!!
+
+
+
+
+
+
+
+
diff --git a/pages/me/myBackImg.nvue b/pages/me/myBackImg.nvue
new file mode 100644
index 00000000..fd5c8f97
--- /dev/null
+++ b/pages/me/myBackImg.nvue
@@ -0,0 +1,170 @@
+
+
+
+
+
+ 更换背景
+
+
+ 返回
+
+
+
+
+
+
+
+
diff --git a/pages/me/myFace.vue b/pages/me/myFace.vue
new file mode 100644
index 00000000..9719fa93
--- /dev/null
+++ b/pages/me/myFace.vue
@@ -0,0 +1,160 @@
+
+
+
+
+
+ 更换头像
+
+
+ 返回
+
+
+
+
+
+
+
+
diff --git a/pages/me/myFans.nvue b/pages/me/myFans.nvue
new file mode 100644
index 00000000..ec094378
--- /dev/null
+++ b/pages/me/myFans.nvue
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+ {{ f.nickname }}
+
+
+
+
+ 你
+
+
+
+ 关注
+
+
+
+
+ 回粉
+
+
+
+
+ 已关注
+
+
+
+
+ 互关
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/me/myFollows.nvue b/pages/me/myFollows.nvue
new file mode 100644
index 00000000..73c8d57c
--- /dev/null
+++ b/pages/me/myFollows.nvue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+ {{ f.nickname }}
+
+
+
+
+ 你
+
+
+
+ 关注
+
+
+
+
+ 已关注
+
+
+
+
+ 互关
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/me/myInfo.vue b/pages/me/myInfo.vue
new file mode 100644
index 00000000..bffc6cbd
--- /dev/null
+++ b/pages/me/myInfo.vue
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+
+ 昵称
+
+
+ {{ myInfo.nickname }}
+
+
+
+
+
+
+ 视频号
+
+
+ {{ myInfo.imoocNum }}
+
+
+
+
+
+
+ 性别
+
+ 男
+ 女
+ 保密
+
+
+
+
+
+ 生日
+
+
+ {{ getGraceDateStr(new Date(myInfo.birthday)) }}
+
+
+
+
+
+
+ 所在地
+
+
+ {{ myInfo.province == myInfo.city ? "" : myInfo.province + "·"
+ }}{{ myInfo.city == "" ? "" : myInfo.city
+ }}{{ myInfo.district == "" ? "" : "·" + myInfo.district }}
+
+
+
+
+
+
+ 简介
+
+
+ {{ myInfo.description }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/me/vlog.vue b/pages/me/vlog.vue
new file mode 100644
index 00000000..70087b87
--- /dev/null
+++ b/pages/me/vlog.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/me/vlogerInfo.vue b/pages/me/vlogerInfo.vue
new file mode 100644
index 00000000..e69de29b
diff --git a/uni_modules/Sansnn-uQRCode/changelog.md b/uni_modules/Sansnn-uQRCode/changelog.md
new file mode 100644
index 00000000..b5661480
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/changelog.md
@@ -0,0 +1,10 @@
+## 2.0.23(2021-08-09)
+
+## 2.0.22(2021-08-09)
+
+## 2.0.21(2021-07-28)
+
+## 2.0.2(2021-07-28)
+2.0.2 新增延迟绘制。
+## 2.0.1(2021-07-26)
+2.0.1 调整为uni_modules目录规范。
diff --git a/uni_modules/Sansnn-uQRCode/components/uqrcode/common/uqrcode.js b/uni_modules/Sansnn-uQRCode/components/uqrcode/common/uqrcode.js
new file mode 100644
index 00000000..fcc4635e
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/uqrcode/common/uqrcode.js
@@ -0,0 +1,1376 @@
+//---------------------------------------------------------------------
+// github https://github.com/Sansnn/uQRCode
+// version 2.0.23
+//---------------------------------------------------------------------
+
+let uQRCode = {};
+
+(function() {
+ //---------------------------------------------------------------------
+ // QRCode for JavaScript
+ //
+ // Copyright (c) 2009 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word "QR Code" is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ //---------------------------------------------------------------------
+ // QR8bitByte
+ //---------------------------------------------------------------------
+
+ function QR8bitByte(data) {
+ this.mode = QRMode.MODE_8BIT_BYTE;
+ this.data = data;
+ }
+
+ QR8bitByte.prototype = {
+
+ getLength: function(buffer) {
+ return this.data.length;
+ },
+
+ write: function(buffer) {
+ for (var i = 0; i < this.data.length; i++) {
+ // not JIS ...
+ buffer.put(this.data.charCodeAt(i), 8);
+ }
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRCode
+ //---------------------------------------------------------------------
+
+ function QRCode(typeNumber, errorCorrectLevel) {
+ this.typeNumber = typeNumber;
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.modules = null;
+ this.moduleCount = 0;
+ this.dataCache = null;
+ this.dataList = new Array();
+ }
+
+ QRCode.prototype = {
+
+ addData: function(data) {
+ var newData = new QR8bitByte(data);
+ this.dataList.push(newData);
+ this.dataCache = null;
+ },
+
+ isDark: function(row, col) {
+ if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+ throw new Error(row + "," + col);
+ }
+ return this.modules[row][col];
+ },
+
+ getModuleCount: function() {
+ return this.moduleCount;
+ },
+
+ make: function() {
+ // Calculate automatically typeNumber if provided is < 1
+ if (this.typeNumber < 1) {
+ var typeNumber = 1;
+ for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ for (var i = 0; i < this.dataList.length; i++) {
+ var data = this.dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+ if (buffer.getLengthInBits() <= totalDataCount * 8)
+ break;
+ }
+ this.typeNumber = typeNumber;
+ }
+ this.makeImpl(false, this.getBestMaskPattern());
+ },
+
+ makeImpl: function(test, maskPattern) {
+
+ this.moduleCount = this.typeNumber * 4 + 17;
+ this.modules = new Array(this.moduleCount);
+
+ for (var row = 0; row < this.moduleCount; row++) {
+
+ this.modules[row] = new Array(this.moduleCount);
+
+ for (var col = 0; col < this.moduleCount; col++) {
+ this.modules[row][col] = null; //(col + row) % 3;
+ }
+ }
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this.typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this.dataCache == null) {
+ this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+ }
+
+ this.mapData(this.dataCache, maskPattern);
+ },
+
+ setupPositionProbePattern: function(row, col) {
+
+ for (var r = -1; r <= 7; r++) {
+
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c++) {
+
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ },
+
+ getBestMaskPattern: function() {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i++) {
+
+ this.makeImpl(true, i);
+
+ var lostPoint = QRUtil.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ },
+
+ createMovieClip: function(target_mc, instance_name, depth) {
+
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+ var cs = 1;
+
+ this.make();
+
+ for (var row = 0; row < this.modules.length; row++) {
+
+ var y = row * cs;
+
+ for (var col = 0; col < this.modules[row].length; col++) {
+
+ var x = col * cs;
+ var dark = this.modules[row][col];
+
+ if (dark) {
+ qr_mc.beginFill(0, 100);
+ qr_mc.moveTo(x, y);
+ qr_mc.lineTo(x + cs, y);
+ qr_mc.lineTo(x + cs, y + cs);
+ qr_mc.lineTo(x, y + cs);
+ qr_mc.endFill();
+ }
+ }
+ }
+
+ return qr_mc;
+ },
+
+ setupTimingPattern: function() {
+
+ for (var r = 8; r < this.moduleCount - 8; r++) {
+ if (this.modules[r][6] != null) {
+ continue;
+ }
+ this.modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < this.moduleCount - 8; c++) {
+ if (this.modules[6][c] != null) {
+ continue;
+ }
+ this.modules[6][c] = (c % 2 == 0);
+ }
+ },
+
+ setupPositionAdjustPattern: function() {
+
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+ for (var i = 0; i < pos.length; i++) {
+
+ for (var j = 0; j < pos.length; j++) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (this.modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r++) {
+
+ for (var c = -2; c <= 2; c++) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2 ||
+ (r == 0 && c == 0)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ },
+
+ setupTypeNumber: function(test) {
+
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ },
+
+ setupTypeInfo: function(test, maskPattern) {
+
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
+ var bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ this.modules[i][8] = mod;
+ } else if (i < 8) {
+ this.modules[i + 1][8] = mod;
+ } else {
+ this.modules[this.moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ this.modules[8][this.moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this.modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this.modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this.modules[this.moduleCount - 8][8] = (!test);
+
+ },
+
+ mapData: function(data, maskPattern) {
+
+ var inc = -1;
+ var row = this.moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col--;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c++) {
+
+ if (this.modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this.modules[row][col - c] = dark;
+ bitIndex--;
+
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this.moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+
+ }
+
+ };
+
+ QRCode.PAD0 = 0xEC;
+ QRCode.PAD1 = 0x11;
+
+ QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+
+ for (var i = 0; i < dataList.length; i++) {
+ var data = dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error("code length overflow. (" +
+ buffer.getLengthInBits() +
+ ">" +
+ totalDataCount * 8 +
+ ")");
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD1, 8);
+ }
+
+ return QRCode.createBytes(buffer, rsBlocks);
+ }
+
+ QRCode.createBytes = function(buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r++) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i++) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = dcdata[r][i];
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+
+ }
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+
+ var QRMode = {
+ MODE_NUMBER: 1 << 0,
+ MODE_ALPHA_NUM: 1 << 1,
+ MODE_8BIT_BYTE: 1 << 2,
+ MODE_KANJI: 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+
+ var QRErrorCorrectLevel = {
+ L: 1,
+ M: 0,
+ Q: 3,
+ H: 2
+ };
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+
+ var QRMaskPattern = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ var QRUtil = {
+
+ PATTERN_POSITION_TABLE: [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ],
+
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+ getBCHTypeInfo: function(data) {
+ var d = data << 10;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+ d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+ }
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
+ },
+
+ getBCHTypeNumber: function(data) {
+ var d = data << 12;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+ d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+ }
+ return (data << 12) | d;
+ },
+
+ getBCHDigit: function(data) {
+
+ var digit = 0;
+
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+
+ return digit;
+ },
+
+ getPatternPosition: function(typeNumber) {
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+ },
+
+ getMask: function(maskPattern, i, j) {
+
+ switch (maskPattern) {
+
+ case QRMaskPattern.PATTERN000:
+ return (i + j) % 2 == 0;
+ case QRMaskPattern.PATTERN001:
+ return i % 2 == 0;
+ case QRMaskPattern.PATTERN010:
+ return j % 3 == 0;
+ case QRMaskPattern.PATTERN011:
+ return (i + j) % 3 == 0;
+ case QRMaskPattern.PATTERN100:
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+ case QRMaskPattern.PATTERN101:
+ return (i * j) % 2 + (i * j) % 3 == 0;
+ case QRMaskPattern.PATTERN110:
+ return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case QRMaskPattern.PATTERN111:
+ return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default:
+ throw new Error("bad maskPattern:" + maskPattern);
+ }
+ },
+
+ getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+ var a = new QRPolynomial([1], 0);
+
+ for (var i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+ }
+
+ return a;
+ },
+
+ getLengthInBits: function(mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 10;
+ case QRMode.MODE_ALPHA_NUM:
+ return 9;
+ case QRMode.MODE_8BIT_BYTE:
+ return 8;
+ case QRMode.MODE_KANJI:
+ return 8;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 12;
+ case QRMode.MODE_ALPHA_NUM:
+ return 11;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 10;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 14;
+ case QRMode.MODE_ALPHA_NUM:
+ return 13;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 12;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else {
+ throw new Error("type:" + type);
+ }
+ },
+
+ getLostPoint: function(qrCode) {
+
+ var moduleCount = qrCode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row++) {
+
+ for (var col = 0; col < moduleCount; col++) {
+
+ var sameCount = 0;
+ var dark = qrCode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r++) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c++) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row++) {
+ for (var col = 0; col < moduleCount - 1; col++) {
+ var count = 0;
+ if (qrCode.isDark(row, col)) count++;
+ if (qrCode.isDark(row + 1, col)) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row++) {
+ for (var col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row, col + 1) &&
+ qrCode.isDark(row, col + 2) &&
+ qrCode.isDark(row, col + 3) &&
+ qrCode.isDark(row, col + 4) &&
+ !qrCode.isDark(row, col + 5) &&
+ qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row + 1, col) &&
+ qrCode.isDark(row + 2, col) &&
+ qrCode.isDark(row + 3, col) &&
+ qrCode.isDark(row + 4, col) &&
+ !qrCode.isDark(row + 5, col) &&
+ qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ var QRMath = {
+
+ glog: function(n) {
+
+ if (n < 1) {
+ throw new Error("glog(" + n + ")");
+ }
+
+ return QRMath.LOG_TABLE[n];
+ },
+
+ gexp: function(n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return QRMath.EXP_TABLE[n];
+ },
+
+ EXP_TABLE: new Array(256),
+
+ LOG_TABLE: new Array(256)
+
+ };
+
+ for (var i = 0; i < 8; i++) {
+ QRMath.EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i++) {
+ QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+ QRMath.EXP_TABLE[i - 5] ^
+ QRMath.EXP_TABLE[i - 6] ^
+ QRMath.EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i++) {
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+ }
+
+ //---------------------------------------------------------------------
+ // QRPolynomial
+ //---------------------------------------------------------------------
+
+ function QRPolynomial(num, shift) {
+
+ if (num.length == undefined) {
+ throw new Error(num.length + "/" + shift);
+ }
+
+ var offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i++) {
+ this.num[i] = num[i + offset];
+ }
+ }
+
+ QRPolynomial.prototype = {
+
+ get: function(index) {
+ return this.num[index];
+ },
+
+ getLength: function() {
+ return this.num.length;
+ },
+
+ multiply: function(e) {
+
+ var num = new Array(this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < this.getLength(); i++) {
+ for (var j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+ }
+ }
+
+ return new QRPolynomial(num, 0);
+ },
+
+ mod: function(e) {
+
+ if (this.getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+ var num = new Array(this.getLength());
+
+ for (var i = 0; i < this.getLength(); i++) {
+ num[i] = this.get(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+ }
+
+ // recursive call
+ return new QRPolynomial(num, 0).mod(e);
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ function QRRSBlock(totalCount, dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ QRRSBlock.RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16],
+
+ // 11
+ [4, 101, 81],
+ [1, 80, 50, 4, 81, 51],
+ [4, 50, 22, 4, 51, 23],
+ [3, 36, 12, 8, 37, 13],
+
+ // 12
+ [2, 116, 92, 2, 117, 93],
+ [6, 58, 36, 2, 59, 37],
+ [4, 46, 20, 6, 47, 21],
+ [7, 42, 14, 4, 43, 15],
+
+ // 13
+ [4, 133, 107],
+ [8, 59, 37, 1, 60, 38],
+ [8, 44, 20, 4, 45, 21],
+ [12, 33, 11, 4, 34, 12],
+
+ // 14
+ [3, 145, 115, 1, 146, 116],
+ [4, 64, 40, 5, 65, 41],
+ [11, 36, 16, 5, 37, 17],
+ [11, 36, 12, 5, 37, 13],
+
+ // 15
+ [5, 109, 87, 1, 110, 88],
+ [5, 65, 41, 5, 66, 42],
+ [5, 54, 24, 7, 55, 25],
+ [11, 36, 12],
+
+ // 16
+ [5, 122, 98, 1, 123, 99],
+ [7, 73, 45, 3, 74, 46],
+ [15, 43, 19, 2, 44, 20],
+ [3, 45, 15, 13, 46, 16],
+
+ // 17
+ [1, 135, 107, 5, 136, 108],
+ [10, 74, 46, 1, 75, 47],
+ [1, 50, 22, 15, 51, 23],
+ [2, 42, 14, 17, 43, 15],
+
+ // 18
+ [5, 150, 120, 1, 151, 121],
+ [9, 69, 43, 4, 70, 44],
+ [17, 50, 22, 1, 51, 23],
+ [2, 42, 14, 19, 43, 15],
+
+ // 19
+ [3, 141, 113, 4, 142, 114],
+ [3, 70, 44, 11, 71, 45],
+ [17, 47, 21, 4, 48, 22],
+ [9, 39, 13, 16, 40, 14],
+
+ // 20
+ [3, 135, 107, 5, 136, 108],
+ [3, 67, 41, 13, 68, 42],
+ [15, 54, 24, 5, 55, 25],
+ [15, 43, 15, 10, 44, 16],
+
+ // 21
+ [4, 144, 116, 4, 145, 117],
+ [17, 68, 42],
+ [17, 50, 22, 6, 51, 23],
+ [19, 46, 16, 6, 47, 17],
+
+ // 22
+ [2, 139, 111, 7, 140, 112],
+ [17, 74, 46],
+ [7, 54, 24, 16, 55, 25],
+ [34, 37, 13],
+
+ // 23
+ [4, 151, 121, 5, 152, 122],
+ [4, 75, 47, 14, 76, 48],
+ [11, 54, 24, 14, 55, 25],
+ [16, 45, 15, 14, 46, 16],
+
+ // 24
+ [6, 147, 117, 4, 148, 118],
+ [6, 73, 45, 14, 74, 46],
+ [11, 54, 24, 16, 55, 25],
+ [30, 46, 16, 2, 47, 17],
+
+ // 25
+ [8, 132, 106, 4, 133, 107],
+ [8, 75, 47, 13, 76, 48],
+ [7, 54, 24, 22, 55, 25],
+ [22, 45, 15, 13, 46, 16],
+
+ // 26
+ [10, 142, 114, 2, 143, 115],
+ [19, 74, 46, 4, 75, 47],
+ [28, 50, 22, 6, 51, 23],
+ [33, 46, 16, 4, 47, 17],
+
+ // 27
+ [8, 152, 122, 4, 153, 123],
+ [22, 73, 45, 3, 74, 46],
+ [8, 53, 23, 26, 54, 24],
+ [12, 45, 15, 28, 46, 16],
+
+ // 28
+ [3, 147, 117, 10, 148, 118],
+ [3, 73, 45, 23, 74, 46],
+ [4, 54, 24, 31, 55, 25],
+ [11, 45, 15, 31, 46, 16],
+
+ // 29
+ [7, 146, 116, 7, 147, 117],
+ [21, 73, 45, 7, 74, 46],
+ [1, 53, 23, 37, 54, 24],
+ [19, 45, 15, 26, 46, 16],
+
+ // 30
+ [5, 145, 115, 10, 146, 116],
+ [19, 75, 47, 10, 76, 48],
+ [15, 54, 24, 25, 55, 25],
+ [23, 45, 15, 25, 46, 16],
+
+ // 31
+ [13, 145, 115, 3, 146, 116],
+ [2, 74, 46, 29, 75, 47],
+ [42, 54, 24, 1, 55, 25],
+ [23, 45, 15, 28, 46, 16],
+
+ // 32
+ [17, 145, 115],
+ [10, 74, 46, 23, 75, 47],
+ [10, 54, 24, 35, 55, 25],
+ [19, 45, 15, 35, 46, 16],
+
+ // 33
+ [17, 145, 115, 1, 146, 116],
+ [14, 74, 46, 21, 75, 47],
+ [29, 54, 24, 19, 55, 25],
+ [11, 45, 15, 46, 46, 16],
+
+ // 34
+ [13, 145, 115, 6, 146, 116],
+ [14, 74, 46, 23, 75, 47],
+ [44, 54, 24, 7, 55, 25],
+ [59, 46, 16, 1, 47, 17],
+
+ // 35
+ [12, 151, 121, 7, 152, 122],
+ [12, 75, 47, 26, 76, 48],
+ [39, 54, 24, 14, 55, 25],
+ [22, 45, 15, 41, 46, 16],
+
+ // 36
+ [6, 151, 121, 14, 152, 122],
+ [6, 75, 47, 34, 76, 48],
+ [46, 54, 24, 10, 55, 25],
+ [2, 45, 15, 64, 46, 16],
+
+ // 37
+ [17, 152, 122, 4, 153, 123],
+ [29, 74, 46, 14, 75, 47],
+ [49, 54, 24, 10, 55, 25],
+ [24, 45, 15, 46, 46, 16],
+
+ // 38
+ [4, 152, 122, 18, 153, 123],
+ [13, 74, 46, 32, 75, 47],
+ [48, 54, 24, 14, 55, 25],
+ [42, 45, 15, 32, 46, 16],
+
+ // 39
+ [20, 147, 117, 4, 148, 118],
+ [40, 75, 47, 7, 76, 48],
+ [43, 54, 24, 22, 55, 25],
+ [10, 45, 15, 67, 46, 16],
+
+ // 40
+ [19, 148, 118, 6, 149, 119],
+ [18, 75, 47, 31, 76, 48],
+ [34, 54, 24, 34, 55, 25],
+ [20, 45, 15, 61, 46, 16]
+ ];
+
+ QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+ var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (rsBlock == undefined) {
+ throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" +
+ errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i++) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j++) {
+ list.push(new QRRSBlock(totalCount, dataCount));
+ }
+ }
+
+ return list;
+ }
+
+ QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+ switch (errorCorrectLevel) {
+ case QRErrorCorrectLevel.L:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRErrorCorrectLevel.M:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRErrorCorrectLevel.Q:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRErrorCorrectLevel.H:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default:
+ return undefined;
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // QRBitBuffer
+ //---------------------------------------------------------------------
+
+ function QRBitBuffer() {
+ this.buffer = new Array();
+ this.length = 0;
+ }
+
+ QRBitBuffer.prototype = {
+
+ get: function(index) {
+ var bufIndex = Math.floor(index / 8);
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+ },
+
+ put: function(num, length) {
+ for (var i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+ }
+ },
+
+ getLengthInBits: function() {
+ return this.length;
+ },
+
+ putBit: function(bit) {
+
+ var bufIndex = Math.floor(this.length / 8);
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0);
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+ }
+
+ this.length++;
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // Support Chinese
+ //---------------------------------------------------------------------
+ function utf16To8(text) {
+ var result = '';
+ var c;
+ for (var i = 0; i < text.length; i++) {
+ c = text.charCodeAt(i);
+ if (c >= 0x0001 && c <= 0x007F) {
+ result += text.charAt(i);
+ } else if (c > 0x07FF) {
+ result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+ result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ } else {
+ result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ }
+ }
+ return result;
+ }
+
+ uQRCode = {
+ errorCorrectLevel: QRErrorCorrectLevel,
+
+ defaults: {
+ size: 354,
+ margin: 0,
+ backgroundColor: '#ffffff',
+ foregroundColor: '#000000',
+ fileType: 'png', // 'jpg', 'png'
+ errorCorrectLevel: QRErrorCorrectLevel.H,
+ typeNumber: -1,
+ enableDelay: false // 启用延迟绘制
+ },
+
+ getModules: function(options) {
+ options = Object.assign(this.defaults, options);
+ var qrcode = new QRCode(options.typeNumber, options.errorCorrectLevel);
+ qrcode.addData(utf16To8(options.text));
+ qrcode.make();
+ return qrcode.modules;
+ },
+
+ make: function(options, componentInstance) {
+ return new Promise((reslove, reject) => {
+ options = Object.assign(this.defaults, options);
+ if (!options.canvasId) {
+ throw new Error('uQRCode: Please set canvasId!');
+ }
+ var modules = this.getModules(options);
+ var tileW = (options.size - options.margin * 2) / modules.length;
+ var tileH = tileW;
+ var delay = 0;
+
+ // 创建canvas上下文前增加一点延时,确保canvas组件已渲染
+ setTimeout(() => {
+ var ctx = uni.createCanvasContext(options.canvasId, componentInstance);
+ ctx.setFillStyle(options.backgroundColor);
+ ctx.fillRect(0, 0, options.size, options.size);
+ for (var row = 0; row < modules.length; row++) {
+ for (var col = 0; col < modules.length; col++) {
+ delay = options.enableDelay ? row * modules.length + col + 1 : 0;
+ setTimeout(function(row, col) {
+ // 计算每一个小块的位置
+ var x = Math.round(col * tileW) + options.margin;
+ var y = Math.round(row * tileH) + options.margin;
+ var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
+ var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
+ var style = modules[row][col] ? options.foregroundColor :
+ options.backgroundColor;
+ ctx.setFillStyle(style);
+ ctx.fillRect(x, y, w, h);
+ }, delay, row, col);
+ }
+ }
+
+ // 耗时
+ var time = options.enableDelay ? delay + options.size * 2 + options.margin * 2 + options.text.length : 0;
+ setTimeout(function() {
+ ctx.draw(false, function() {
+ uni.canvasToTempFilePath({
+ canvasId: options.canvasId,
+ fileType: options.fileType,
+ width: options.size,
+ height: options.size,
+ destWidth: options.size,
+ destHeight: options.size,
+ success: function(res) {
+ reslove(Object.assign(res, {
+ time: time + 50
+ }));
+ },
+ fail: function(err) {
+ reject(err);
+ }
+ }, componentInstance);
+ });
+ }, time);
+ }, 50);
+
+
+ });
+ }
+ }
+
+})();
+
+export default uQRCode;
diff --git a/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue b/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue
new file mode 100644
index 00000000..50575292
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/Sansnn-uQRCode/package.json b/uni_modules/Sansnn-uQRCode/package.json
new file mode 100644
index 00000000..5ed666fa
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/package.json
@@ -0,0 +1,78 @@
+{
+ "id": "Sansnn-uQRCode",
+ "displayName": "uQRCode 二维码生成插件",
+ "version": "2.0.23",
+ "description": "uQRCode 是一款使用方式简单,易于扩展的二维码生成插件。",
+ "keywords": [
+ "uQRCode",
+ "二维码",
+ "qrcode"
+],
+ "repository": "https://github.com/Sansnn/uQRCode",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "JS SDK",
+ "通用 SDK"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/readme.md b/uni_modules/Sansnn-uQRCode/readme.md
new file mode 100644
index 00000000..bda5bc6b
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/readme.md
@@ -0,0 +1,167 @@
+# uQRCode
+
+uQRCode 生成方式简单,可扩展性高,如有复杂需求可通过自定义组件或修改源码完成需求。已测试H5、微信小程序、iPhoneXsMax真机。
+
+支持自定义二维码渲染规则,可通过 ``getModules`` 方法得到矩阵信息后,自行实现canvas渲染二维码,如随机颜色、圆点、方块、块与块之间的间距等,详情见示例中的 ``custom``。
+
+支持nvue生成,但暂不支持保存。
+
+### 二维码
+**什么是QR码**
+
+QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。
+
+**QR码的特点**
+
+一是高速读取(QR就是取自“Quick Response”的首字母),通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;
+
+二是高容量、高密度,理论上内容经过压缩处理后可以存7089个数字,4296个字母和数字混合字符,2953个8位字节数据,1817个汉字;
+
+三是支持纠错处理,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:
+- level L : 最大 7% 的错误能够被纠正;
+- level M : 最大 15% 的错误能够被纠正;
+- level Q : 最大 25% 的错误能够被纠正;
+- level H : 最大 30% 的错误能够被纠正;
+
+四是结构化,看似无规则的图形,其实对区域有严格的定义。
+
+更多二维码介绍及原理:[https://blog.csdn.net/jason_ldh/article/details/11801355](https://blog.csdn.net/jason_ldh/article/details/11801355)
+
+### 简单使用
+
+在 ``template`` 中创建 ```` 并设置 ``ref`` 属性
+
+```html
+
+```
+
+在 ``script`` 中调用生成方法
+
+```javascript
+export default {
+ onReady() {
+ this.$refs
+ .uqrcode
+ .make({
+ size: 354,
+ text: 'uQRCode'
+ })
+ .then(res => {
+ // 返回的res与uni.canvasToTempFilePath返回一致
+ console.log(res)
+ })
+ }
+}
+```
+
+### 高级使用
+
+在 ``template`` 中创建 ```` 并设置 ``id``,画布宽高
+
+```html
+
+```
+
+在 ``script`` 中引用js文件并调用生成方法
+
+```javascript
+import uQRCode from '@/components/uqrcode/common/uqrcode.js'
+
+export default {
+ onReady() {
+ uQRCode.make({
+ canvasId: 'qrcode',
+ componentInstance: this,
+ size: 354,
+ margin: 10,
+ text: 'uQRCode',
+ backgroundColor: '#ffffff',
+ foregroundColor: '#ff0000',
+ fileType: 'png',
+ errorCorrectLevel: uQRCode.errorCorrectLevel.H
+ })
+ .then(res => {
+ console.log(res)
+ })
+ }
+}
+```
+
+### 属性说明
+
+|属性名|说明|
+|---|:---|
+|errorCorrectLevel|纠错等级,包含 `errorCorrectLevel.L`、`errorCorrectLevel.M`、`errorCorrectLevel.Q`、`errorCorrectLevel.H` 四个级别,`L`: 最大 7% 的错误能够被纠正;`M`: 最大 15% 的错误能够被纠正;`Q`: 最大 25% 的错误能够被纠正;`H`: 最大 30% 的错误能够被纠正。|
+|defaults|二维码生成参数的默认值。|
+
+### 方法说明
+
+|方法名|说明|
+|---|:---|
+|[make](#makeoptions)|生成二维码。|
+|[getModules](#getModulesoptions)|可以得到二维码矩阵信息,可根据返回的矩阵信息自行实现二维码生成。|
+
+### make(options)
+
+生成二维码
+
+**options参数说明:**
+
+|参数|类型|必填|说明|
+|---|---|---|:---|
+|canvasId|String|是|画布标识,传入 `` 的 `canvas-id`|
+|componentInstance|Object|否|自定义组件实例 `this` ,表示在这个自定义组件下查找拥有 `canvas-id` 的 `` ,如果省略,则不在任何自定义组件内查找|
+|text|String|是|二维码内容|
+|size|Number|否|画布尺寸大小,请与 `` 所设 `width` , `height` 保持一致(默认:`354`)|
+|margin|Number|否|边距,二维码实际尺寸会根据所设边距值进行缩放调整(默认:`0`)|
+|backgroundColor|String|否|背景色,若设置为透明背景, `fileType` 需设置为 `'png'` , 然后设置背景色为 `'rgba(255,255,255,0)'` 即可(默认:`'#ffffff'`)|
+|foregroundColor|String|否|前景色(默认:`'#000000'`)|
+|fileType|String|否|输出图片的类型,只支持 `'jpg'` 和 `'png'`(默认:`'png'`)|
+|errorCorrectLevel|Number|否|纠错等级,参考属性说明 `errorCorrectLevel`(默认:`errorCorrectLevel.H`)|
+|enableDelay|Boolen|否|启用延迟绘制(默认:`false`)|
+
+### getModules(options)
+
+根据内容得到二维码矩阵信息
+
+|参数|类型|必填|说明|
+|---|---|---|:---|
+|text|String|是|二维码内容|
+|errorCorrectLevel|Number|否|纠错等级,参考属性说明 `errorCorrectLevel`(默认:`errorCorrectLevel.H`)|
+
+### 使用建议
+如需在进入页面时生成二维码,建议使用`onReady`,不推荐在`onLoad`中生成。
+
+关于高级使用:canvas在二维码生成中请当做一个生成工具来看待,它的作用仅是绘制出二维码。应把生成回调得到的资源保存并使用,显示用image图片组件,原因是方便操作,例如调整大小,或是H5端长按保存或识别,所以canvas应将它放在看不见的地方。不能用`display:none;overflow:hidden;`隐藏,否则生成空白。这里推荐canvas的隐藏样式代码
+```html
+
+```
+
+### 常见问题
+**二维码生成不完整**
+
+size的单位是px,请尽量避免使用rpx,如果canvas的单位是rpx,那么不同设备屏幕分辨率不一样,rpx转换成px后的画布尺寸不足以放下全部内容,实际绘制图案超出,就会出现不完整或者没有填充完整画布的情况。
+
+另外还可以尝试延迟绘制,``enableDelay`` 设置为 ``true``。
+
+**如何扫码跳转指定网页**
+
+text参数直接放入完整的网页地址即可,例如:`https://ext.dcloud.net.cn/plugin?id=1287`。微信客户端不能是ip地址。
+
+**H5长按识别**
+
+canvas无法长按识别,长按识别需要是图片才行,所以只需将回调过来的资源用image组件显示即可。
+
+### Tips
+- 示例项目中的图片采集于互联网,仅作为案例展示,不作为广告/商业,如有侵权,请告知删除。下载使用的用户,请勿把示例项目中的图片应用到你的项目。
diff --git a/uni_modules/uni-popup/changelog.md b/uni_modules/uni-popup/changelog.md
new file mode 100644
index 00000000..f46daceb
--- /dev/null
+++ b/uni_modules/uni-popup/changelog.md
@@ -0,0 +1,35 @@
+## 1.6.1(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.6.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.5.0(2021-06-23)
+- 新增 mask-click 遮罩层点击事件
+## 1.4.5(2021-06-22)
+- 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug
+## 1.4.4(2021-06-18)
+- 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug
+## 1.4.3(2021-06-08)
+- 修复 错误的 watch 字段
+- 修复 safeArea 属性不生效的问题
+- 修复 点击内容,再点击遮罩无法关闭的Bug
+## 1.4.2(2021-05-12)
+- 新增 组件示例地址
+## 1.4.1(2021-04-29)
+- 修复 组件内放置 input 、textarea 组件,无法聚焦的问题
+## 1.4.0 (2021-04-29)
+- 新增 type 属性的 left\right 值,支持左右弹出
+- 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗
+- 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色
+- 新增 safeArea 属性,是否适配底部安全区
+- 修复 App\h5\微信小程序底部安全区占位不对的Bug
+- 修复 App 端弹出等待的Bug
+- 优化 提升低配设备性能,优化动画卡顿问题
+- 优化 更简单的组件自定义方式
+## 1.2.9(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.2.8(2021-02-05)
+- 调整为uni_modules目录规范
+## 1.2.7(2021-02-05)
+- 调整为uni_modules目录规范
+- 新增 支持 PC 端
+- 新增 uni-popup-message 、uni-popup-dialog扩展组件支持 PC 端
diff --git a/uni_modules/uni-popup/components/uni-popup-comments/uni-popup-comments.vue b/uni_modules/uni-popup/components/uni-popup-comments/uni-popup-comments.vue
new file mode 100644
index 00000000..4c6f86a8
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup-comments/uni-popup-comments.vue
@@ -0,0 +1,728 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js
new file mode 100644
index 00000000..6ef26a26
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false
+ }
+ },
+ mounted () {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del']
+ }
+ const listener = ($event) => {
+ if (this.disable) {
+ return
+ }
+ const keyName = Object.keys(keyNames).find(key => {
+ const keyName = $event.key
+ const value = keyNames[key]
+ return value === keyName || (Array.isArray(value) && value.includes(keyName))
+ })
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {})
+ }, 0)
+ }
+ }
+ document.addEventListener('keyup', listener)
+ this.$once('hook:beforeDestroy', () => {
+ document.removeEventListener('keyup', listener)
+ })
+ },
+ render: () => {}
+}
+// #endif
diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue
new file mode 100644
index 00000000..9ddb8368
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue
new file mode 100644
index 00000000..f4c85e25
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
+
diff --git a/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue
new file mode 100644
index 00000000..3327bf09
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+ 保存到相册
+
+
+
+
+
+
+ 复制链接
+
+
+
+
+
+
+ 二维码
+
+
+
+
+
+
+
+ 转为私密
+
+
+
+
+
+ 转为公开
+
+
+
+
+
+
+
+ 取消
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-popup/components/uni-popup/keypress.js b/uni_modules/uni-popup/components/uni-popup/keypress.js
new file mode 100644
index 00000000..62dda461
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false
+ }
+ },
+ mounted () {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del']
+ }
+ const listener = ($event) => {
+ if (this.disable) {
+ return
+ }
+ const keyName = Object.keys(keyNames).find(key => {
+ const keyName = $event.key
+ const value = keyNames[key]
+ return value === keyName || (Array.isArray(value) && value.includes(keyName))
+ })
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {})
+ }, 0)
+ }
+ }
+ document.addEventListener('keyup', listener)
+ // this.$once('hook:beforeDestroy', () => {
+ // document.removeEventListener('keyup', listener)
+ // })
+ },
+ render: () => {}
+}
+// #endif
diff --git a/uni_modules/uni-popup/components/uni-popup/popup.js b/uni_modules/uni-popup/components/uni-popup/popup.js
new file mode 100644
index 00000000..c4e5781d
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup/popup.js
@@ -0,0 +1,26 @@
+
+export default {
+ data() {
+ return {
+
+ }
+ },
+ created(){
+ this.popup = this.getParent()
+ },
+ methods:{
+ /**
+ * 获取父元素实例
+ */
+ getParent(name = 'uniPopup') {
+ let parent = this.$parent;
+ let parentName = parent.$options.name;
+ while (parentName !== name) {
+ parent = parent.$parent;
+ if (!parent) return false
+ parentName = parent.$options.name;
+ }
+ return parent;
+ },
+ }
+}
diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue
new file mode 100644
index 00000000..508a6cb1
--- /dev/null
+++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue
@@ -0,0 +1,404 @@
+
+
+
+
+
+
diff --git a/uni_modules/uni-popup/package.json b/uni_modules/uni-popup/package.json
new file mode 100644
index 00000000..c69a3338
--- /dev/null
+++ b/uni_modules/uni-popup/package.json
@@ -0,0 +1,85 @@
+{
+ "id": "uni-popup",
+ "displayName": "uni-popup 弹出层",
+ "version": "1.6.1",
+ "description": " Popup 组件,提供常用的弹层",
+ "keywords": [
+ "uni-ui",
+ "弹出层",
+ "弹窗",
+ "popup",
+ "弹框"
+ ],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-transition"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-popup/readme.md b/uni_modules/uni-popup/readme.md
new file mode 100644
index 00000000..d8a08994
--- /dev/null
+++ b/uni_modules/uni-popup/readme.md
@@ -0,0 +1,296 @@
+
+
+## Popup 弹出层
+> **组件名:uni-popup**
+> 代码块: `uPopup`
+> 关联组件:`uni-popup-dialog`,`uni-popup-message`,`uni-popup-share`,`uni-transition`
+
+
+弹出层组件,在应用中弹出一个消息提示窗口、提示框等
+
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - `uni-popup-message` 、 `uni-popup-dialog` 等扩展ui组件,需要和 `uni-popup` 配套使用,暂不支持单独使用
+> - `nvue` 中使用 `uni-popup` 时,尽量将组件置于其他元素后面,避免出现层级问题
+> - `uni-popup` 并不能完全阻止页面滚动,可在打开 `uni-popup` 的时候手动去做一些处理,禁止页面滚动
+> - 如果想在页面渲染完毕后就打开 `uni-popup` ,请在 `onReady` 或 `mounted` 生命周期内调用,确保组件渲染完毕
+> - 在微信小程序开发者工具中,启用真机调试,popup 会延时出现,是因为 setTimeout 在真机调试中的延时问题导致的,预览和发布小程序不会出现此问题
+> - 使用 `npm` 方式引入组件,如果确认引用正确,但是提示未注册组件或显示不正常,请尝试重新编译项目
+> - `uni-popup` 中尽量不要使用 `scroll-view` 嵌套过多的内容,可能会影响组件的性能,导致组件无法打开或者打开卡顿
+> - `uni-popup` 不会覆盖原生 tabbar 和原生导航栏
+> - 组件支持 nvue ,需要在 `manifest.json > app-plus` 节点下配置 `"nvueStyleCompiler" : "uni-app"`
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+
+### 基本用法
+
+**示例**
+
+```html
+
+底部弹出 Popup
+```
+
+```javascript
+export default {
+ methods:{
+ open(){
+ // 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center']
+ this.$refs.popup.open('top')
+ }
+ }
+}
+
+```
+
+### 设置主窗口背景色
+
+在大多数场景下,并不需要设置 `background-color` 属性,因为`uni-popup`的主窗口默认是透明的,在向里面插入内容的时候 ,样式完全交由用户定制,如果设置了背景色 ,例如 `uni-popup-dialog` 中的圆角就很难去实现,不设置背景色,更适合用户去自由发挥。
+
+而也有特例,需要我们主动去设置背景色,例如 `type = 'bottom'` 的时候 ,在异型屏中遇到了底部安全区问题(如 iphone 11),因为 `uni-popup`的主要内容避开了安全区(设置`safe-area:true`),导致底部的颜色我们无法自定义,这时候使用 `background-color` 就可以解决这个问题。
+
+**示例**
+
+```html
+
+底部弹出 Popup
+```
+
+### 禁用打开动画
+在某些场景 ,可能不希望弹层有动画效果 ,只需要将 `animation` 属性设置为 `false` 即可以关闭动画。
+
+**示例**
+
+```html
+
+中间弹出 Popup
+```
+
+### 禁用点击遮罩关闭
+默认情况下,点击遮罩会自动关闭`uni-popup`,如不想点击关闭,只需将`mask-click`设置为`false`,这时候要关闭`uni-popup`,只能手动调用 `close` 方法。
+
+**示例**
+
+```html
+
+
+ Popup
+
+
+```
+
+```javascript
+export default {
+ data() {
+ return {}
+ },
+ onReady() {},
+ methods: {
+ open() {
+ this.$refs.popup.open('top')
+ },
+ close() {
+ this.$refs.popup.close()
+ }
+ }
+}
+
+```
+
+## API
+
+### Popup Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:|:-:|
+|animation|Boolean|true|是否开启动画|
+|type|String|'center'|弹出方式|
+|mask-click|Boolean|true|蒙版点击是否关闭弹窗|
+|background-color|String|'none'|主窗口背景色|
+|safe-area|Boolean|true|是否适配底部安全区|
+
+#### Type Options
+
+|属性名|说明|
+|:-:| :-:|
+|top|顶部弹出 |
+|center|居中弹出|
+|bottom|底部弹出|
+|left|左侧弹出|
+|right|右侧弹出|
+|message|预置样式 :消息提示|
+|dialog|预置样式 :对话框|
+|share|预置样式 :底部弹出分享示例 |
+
+
+### Popup Methods
+
+|方法称名 |说明|参数|
+|:-:|:-:|:-:|
+|open|打开弹出层|open(String:type) ,如果参数可代替 type 属性|
+|close|关闭弹出层 |-|
+
+
+### Popup Events
+
+|事件称名|说明|返回值|
+|:-:|:-:|:-:|
+|change|组件状态发生变化触发|e={show: true|false,type:当前模式}|
+|maskClick|点击遮罩层触发|-|
+
+
+## 扩展组件说明
+`uni-popup` 其实并没有任何样式,只提供基础的动画效果,给用户一个弹出层解决方案,仅仅是这样并不能满足开发需求,所以我们提供了三种基础扩展样式
+
+### uni-popup-message 提示信息
+
+将 `uni-popup` 的`type`属性改为 `message`,并引入对应组件即可使用消息提示 ,*该组件不支持单独使用*
+
+**示例**
+
+```html
+
+
+
+```
+
+### PopupMessage Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:|:-:|
+|type|String|success|消息提示主题|
+|message|String|-|消息提示文字|
+|duration|Number|3000|消息显示时间,超过显示时间组件自动关闭,设置为0 将不会关闭,需手动调用 close 方法关闭|
+
+#### Type Options
+
+|属性名|说明|
+|:-:| :-:|
+|success|成功 |
+|warn|警告|
+|error|失败|
+|info|消息|
+
+### PopupMessage Slots
+
+|名称|说明|
+|:-:|:-:|
+|default|消息内容,会覆盖 message 属性|
+
+### uni-popup-dialog 对话框
+
+将 `uni-popup` 的`type`属性改为 `dialog`,并引入对应组件即可使用对话框 ,*该组件不支持单独使用*
+
+**示例**
+
+```html
+
+
+
+
+```
+
+```javascript
+export default {
+ methods: {
+ open() {
+ this.$refs.popup.open()
+ },
+ /**
+ * 点击取消按钮触发
+ * @param {Object} done
+ */
+ close() {
+ // TODO 做一些其他的事情,before-close 为true的情况下,手动执行 close 才会关闭对话框
+ // ...
+ this.$refs.popup.close()
+ },
+ /**
+ * 点击确认按钮触发
+ * @param {Object} done
+ * @param {Object} value
+ */
+ confirm(value) {
+ // 输入框的值
+ console.log(value)
+ // TODO 做一些其他的事情,手动执行 close 才会关闭对话框
+ // ...
+ this.$refs.popup.close()
+ }
+ }
+}
+```
+
+### PopupDialog Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:|:-:|
+|type|String|success|对话框标题主题,可选值: success/warn/info/error|
+|mode|String|base| 对话框模式,可选值:base(提示对话框)/input(可输入对话框)|
+|title|String|-|对话框标题|
+|content|String|-|对话框内容,base模式下生效|
+|value| String\Number|-|输入框默认值,input模式下生效|
+|placeholder|String|-|输入框提示文字,input模式下生效|
+|before-close|Boolean|false | 是否拦截按钮事件,如为true,则不会关闭对话框,关闭需要手动执行 uni-popup 的 close 方法|
+
+#### PopupDialog Events
+
+|事件称名 |说明|返回值|
+|:-:|:-:|:-:|
+|close|点击dialog取消按钮触发|-|
+|confirm|点击dialog确定按钮触发|e={value:input模式下输入框的值}|
+
+### PopupDialog Slots
+
+|名称|说明|
+|:-:|:-:|
+|default|自定义内容,回覆盖原有的内容显示|
+
+### uni-popup-share 分享示例
+
+分享示例,不作为最终可使用的组件,只做为样式组件,供用户自行修改,`后续的开发计划是实现实际的分享逻辑,参数可配置`。
+
+将 `uni-popup` 的 `type` 属性改为 `share`,并引入对应组件即可使用 ,*该组件不支持单独使用*
+
+**示例**
+
+```html
+
+
+
+```
+
+### PopupShare Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:| :-: |
+|title|String|-|分享弹窗标题|
+|before-close|Boolean|false | 是否拦截按钮事件,如为true,则不会关闭对话框,关闭需要手动执行 uni-popup 的 close 方法|
+
+### PopupShare Events
+
+|事件称名|说明|返回值|
+|:-:|:-:|:-:|
+|select|选择触发|e = {item,index}:所选参数|
+
+**Tips**
+- share 分享组件,只是作为一个扩展示例,如果需要修改数据源,请到组件内修改
+
+## 帮助
+在使用中如遇到无法解决的问题,请提 [Issues](https://github.com/dcloudio/uni-ui/issues) 给我们。
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/popup/popup](https://hellouniapp.dcloud.net.cn/pages/extUI/popup/popup)
\ No newline at end of file
diff --git a/uni_modules/uni-transition/changelog.md b/uni_modules/uni-transition/changelog.md
new file mode 100644
index 00000000..dca8178c
--- /dev/null
+++ b/uni_modules/uni-transition/changelog.md
@@ -0,0 +1,13 @@
+## 1.2.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.1(2021-05-12)
+- 新增 示例地址
+- 修复 示例项目缺少组件的Bug
+## 1.1.0(2021-04-22)
+- 新增 通过方法自定义动画
+- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式
+- 优化 动画触发逻辑,使动画更流畅
+- 优化 支持单独的动画类型
+- 优化 文档示例
+## 1.0.2(2021-02-05)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/uni_modules/uni-transition/components/uni-transition/createAnimation.js
new file mode 100644
index 00000000..5f54365e
--- /dev/null
+++ b/uni_modules/uni-transition/components/uni-transition/createAnimation.js
@@ -0,0 +1,128 @@
+// const defaultOption = {
+// duration: 300,
+// timingFunction: 'linear',
+// delay: 0,
+// transformOrigin: '50% 50% 0'
+// }
+// #ifdef APP-NVUE
+const nvueAnimation = uni.requireNativePlugin('animation')
+// #endif
+class MPAnimation {
+ constructor(options, _this) {
+ this.options = options
+ this.animation = uni.createAnimation(options)
+ this.currentStepAnimates = {}
+ this.next = 0
+ this.$ = _this
+
+ }
+
+ _nvuePushAnimates(type, args) {
+ let aniObj = this.currentStepAnimates[this.next]
+ let styles = {}
+ if (!aniObj) {
+ styles = {
+ styles: {},
+ config: {}
+ }
+ } else {
+ styles = aniObj
+ }
+ if (animateTypes1.includes(type)) {
+ if (!styles.styles.transform) {
+ styles.styles.transform = ''
+ }
+ let unit = ''
+ if(type === 'rotate'){
+ unit = 'deg'
+ }
+ styles.styles.transform += `${type}(${args+unit}) `
+ } else {
+ styles.styles[type] = `${args}`
+ }
+ this.currentStepAnimates[this.next] = styles
+ }
+ _animateRun(styles = {}, config = {}) {
+ let ref = this.$.$refs['ani'].ref
+ if (!ref) return
+ return new Promise((resolve, reject) => {
+ nvueAnimation.transition(ref, {
+ styles,
+ ...config
+ }, res => {
+ resolve()
+ })
+ })
+ }
+
+ _nvueNextAnimate(animates, step = 0, fn) {
+ let obj = animates[step]
+ if (obj) {
+ let {
+ styles,
+ config
+ } = obj
+ this._animateRun(styles, config).then(() => {
+ step += 1
+ this._nvueNextAnimate(animates, step, fn)
+ })
+ } else {
+ this.currentStepAnimates = {}
+ typeof fn === 'function' && fn()
+ this.isEnd = true
+ }
+ }
+
+ step(config = {}) {
+ // #ifndef APP-NVUE
+ this.animation.step(config)
+ // #endif
+ // #ifdef APP-NVUE
+ this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
+ this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
+ this.next++
+ // #endif
+ return this
+ }
+
+ run(fn) {
+ // #ifndef APP-NVUE
+ this.$.animationData = this.animation.export()
+ this.$.timer = setTimeout(() => {
+ typeof fn === 'function' && fn()
+ }, this.$.durationTime)
+ // #endif
+ // #ifdef APP-NVUE
+ this.isEnd = false
+ let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref
+ if(!ref) return
+ this._nvueNextAnimate(this.currentStepAnimates, 0, fn)
+ this.next = 0
+ // #endif
+ }
+}
+
+
+const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
+ 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
+ 'translateZ'
+]
+const animateTypes2 = ['opacity', 'backgroundColor']
+const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom']
+animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
+ MPAnimation.prototype[type] = function(...args) {
+ // #ifndef APP-NVUE
+ this.animation[type](...args)
+ // #endif
+ // #ifdef APP-NVUE
+ this._nvuePushAnimates(type, args)
+ // #endif
+ return this
+ }
+})
+
+export function createAnimation(option, _this) {
+ if(!_this) return
+ clearTimeout(_this.timer)
+ return new MPAnimation(option, _this)
+}
diff --git a/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue
new file mode 100644
index 00000000..69ff9d98
--- /dev/null
+++ b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-transition/package.json b/uni_modules/uni-transition/package.json
new file mode 100644
index 00000000..0a709c9a
--- /dev/null
+++ b/uni_modules/uni-transition/package.json
@@ -0,0 +1,83 @@
+{
+ "id": "uni-transition",
+ "displayName": "uni-transition 过渡动画",
+ "version": "1.2.0",
+ "description": "元素的简单过渡动画",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "动画",
+ "过渡",
+ "过渡动画"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-transition/readme.md b/uni_modules/uni-transition/readme.md
new file mode 100644
index 00000000..f3986238
--- /dev/null
+++ b/uni_modules/uni-transition/readme.md
@@ -0,0 +1,397 @@
+
+
+## Transition 过渡动画
+> **组件名:uni-transition**
+> 代码块: `uTransition`
+
+
+元素过渡动画
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - rotate 旋转动画不需要填写 deg 单位,在小程序上填写单位动画不会执行
+> - NVUE 下修改宽高动画,不能定位到中心点
+> - 百度小程序下修改宽高 ,可能会影响其他动画,需注意
+> - nvue 不支持 costom-class , 请使用 styles
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+
+
+
+
+
+```
+
+### 样式覆盖
+
+**注意:`nvue` 不支持 `custom-class` 属性 ,需要使用 `styles` 属性进行兼容**
+
+使用 `custom-class` 属性绑定样式,可以自定义 `uni-transition` 的样式
+
+```html
+
+
+
+
+
+
+
+
+```
+
+
+如果使用 `styles` 注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
+
+```html
+
+
+
+
+
+
+```
+
+### 自定义动画
+当内置动画类型不能满足需求的时候 ,可以使用 `step()` 和 `run()` 自定义动画,入参以及具体用法参考下方属性说明
+
+`init()` 方法可以覆盖默认配置
+
+
+```html
+
+
+
+
+
+
+
+
+```
+
+
+## API
+
+### Transition Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-:|
+|show |Boolean|false |控制组件显示或隐藏 |
+|mode-class |Array/String |- |内置过渡动画类型 |
+|custom-class |String |- |自定义类名 |
+|duration |Number |300 |过渡动画持续时间 |
+|styles |Object |- |组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red` |
+
+#### mode-class 内置过渡动画类型说明
+**格式为** :`'fade'` 或者 `['fade','slide-top']`
+
+|属性名 |说明 |
+|:-: |:-: |
+|fade |渐隐渐出过渡 |
+|slide-top |由上至下过渡 |
+|slide-right |由右至左过渡 |
+|slide-bottom |由下至上过渡 |
+|slide-left |由左至右过渡 |
+|zoom-in |由小到大过渡 |
+|zoom-out |由大到小过渡 |
+
+**注意**
+
+组合使用时,同一种类型相反的过渡动画如(slide-top、slide-bottom)同时使用时,只有最后一个生效
+
+### Transition Events
+
+|事件名 |说明 |返回值 |
+|:-: |:-: |:-: |
+|click |点击组件触发 |- |
+|change |过渡动画结束时触发 | e = {detail:true} |
+
+### Transition Methons
+
+|方法名|说明|参数|
+|:-:|:-:|:-:|
+|init()|手动初始化配置|Function(OBJECT:config)|
+|step()|动画队列|Function(OBJECT:type,OBJECT:config)|
+|run()|执行动画|Function(FUNCTION:callback) |
+
+### init(OBJECT:config)
+**通过 ref 调用方法**
+
+手动设置动画配置,需要在页面渲染完毕后调用
+
+```javascript
+this.$refs.ani.init({
+ duration: 1000,
+ timingFunction:'ease',
+ delay:500,
+ transformOrigin:'left center'
+})
+```
+
+### step(OBJECT:type,OBJECT:config) 动画队列
+**通过 ref 调用方法**
+
+调用 `step()` 来表示一组动画完成,`step` 第一个参数可以传入任意多个动画方法,一组动画中的所有动画会同时开始,一组动画完成后才会进行下一组动画。`step` 第二个参数可以传入一个跟 `uni.createAnimation()` 一样的配置参数用于指定当前组动画的配置。
+
+Tips
+- 第一个参数支持的动画参考下面的 `支持的动画`
+- 第二个参数参考下面的 `动画配置`,可省略,如果省略继承`init`的配置
+
+
+```javascript
+this.$refs.ani.step({
+ translateX: '100px'
+},{
+ duration: 1000,
+ timingFunction:'ease',
+ delay:500,
+ transformOrigin:'left center'
+})
+```
+
+### run(FUNCTION:callback) 执行动画
+**通过 ref 调用方法**
+
+在执行 `step()` 后,需要调用 `run()` 来运行动画 ,否则动画会一直等待
+
+`run()` 方法可以传入一个 `callback` 函数 ,会在所有动画执行完毕后回调
+
+```javascript
+this.$refs.ani.step({
+ translateX: '100px'
+})
+this.$refs.ani.run(()=>{
+ console.log('动画执行完毕')
+})
+
+```
+
+### 动画配置
+动画配置 , `init()` 与 `step()` 第二个参数配置相同 ,如果配置`step() `第二个参数,将会覆盖 `init()` 的配置
+
+|属性名|值|必填|默认值|说明|平台差异|
+|:-:|:-:|:-:|:-:|:-:|:-:|
+|duration|Number|否|400|动画持续时间,单位ms|-|
+|timingFunction|String|否|"linear"|定义动画的效果|-|
+|delay|Number|否|0|动画延迟时间,单位 ms|-|
+|needLayout|Boolean|否|false |动画执行是否影响布局|仅 nvue 支持|
+|transformOrigin|String |否|"center center"|设置 [transform-origin](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin)|-|
+
+
+### timingFunction 属性说明
+
+|值|说明|平台差异|
+|:-:|:-:|:-:|
+|linear|动画从头到尾的速度是相同的|-|
+|ease|动画以低速开始,然后加快,在结束前变慢|-|
+|ease-in| 动画以低速开始|-|
+|ease-in-out| 动画以低速开始和结束|-|
+|ease-out|动画以低速结束|-|
+|step-start|动画第一帧就跳至结束状态直到结束|nvue不支持|
+|step-end|动画一直保持开始状态,最后一帧跳到结束状态|nvue不支持|
+
+```javascript
+// init 配置
+this.$refs.ani.init({
+ duration: 1000,
+ timingFunction:'ease',
+ delay:500,
+ transformOrigin:'left center'
+})
+// step 配置
+this.$refs.ani.step({
+ translateX: '100px'
+},{
+ duration: 1000,
+ timingFunction:'ease',
+ delay:500,
+ transformOrigin:'left center'
+})
+```
+
+### 支持的动画
+动画方法
+
+如果同一个动画方法有多个值,多个值使用数组分隔
+
+```javascript
+this.$refs.ani.step({
+ width:'100px',
+ scale: [1.2,0.8],
+})
+```
+
+**样式:**
+
+|属性名|值|说明|平台差异|
+|:-:|:-:|:-:|:-:|
+|opacity|value|透明度,参数范围 0~1|-|
+|backgroundColor|color|颜色值|-|
+|width|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|-|
+|height|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|-|
+|top|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|nvue 不支持|
+|left|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|nvue 不支持|
+|bottom|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|nvue 不支持|
+|right|length|长度值,如果传入 Number 则默认使用 px,可传入其他自定义单位的长度值|nvue 不支持|
+
+```javascript
+this.$refs.ani.step({
+ opacity: 1,
+ backgroundColor: '#ff5a5f',
+ widht:'100px',
+ height:'50rpx',
+})
+```
+
+**旋转:**
+
+旋转属性的值不需要填写单位
+
+|属性名|值|说明|平台差异 |
+|:-:|:-:|:-:|:-:|
+|rotate|deg|deg的范围-180~180,从原点顺时针旋转一个deg角度 |-|
+|rotateX|deg|deg的范围-180~180,在X轴旋转一个deg角度 |-|
+|rotateY|deg|deg的范围-180~180,在Y轴旋转一个deg角度 |-|
+|rotateZ|deg|deg的范围-180~180,在Z轴旋转一个deg角度 |nvue不支持|
+|rotate3d|x,y,z,deg| 同 [transform-function rotate3d](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d()) |nvue不支持|
+
+```javascript
+this.$refs.ani.step({
+ rotateX: 45,
+ rotateY: 45
+})
+```
+
+**缩放:**
+
+|属性名|值|说明|平台差异|
+|:-:|:-:|:-: |:-:|
+|scale|sx,[sy]|一个参数时,表示在X轴、Y轴同时缩放sx倍数;两个参数时表示在X轴缩放sx倍数,在Y轴缩放sy倍数|-|
+|scaleX|sx|在X轴缩放sx倍数|-|
+|scaleY|sy|在Y轴缩放sy倍数|-|
+|scaleZ|sz|在Z轴缩放sy倍数|nvue不支持|
+|scale3d|sx,sy,sz|在X轴缩放sx倍数,在Y轴缩放sy倍数,在Z轴缩放sz倍数|nvue不支持|
+
+```javascript
+this.$refs.ani.step({
+ scale: [1.2,0.8]
+})
+```
+
+**偏移:**
+
+|属性名|值|说明|平台差异|
+|:-:|:-:|:-:|:-:|
+|translate|tx,[ty]|一个参数时,表示在X轴偏移tx,单位px;两个参数时,表示在X轴偏移tx,在Y轴偏移ty,单位px。|-|
+|translateX|tx| 在X轴偏移tx,单位px|-|
+|translateY|ty| 在Y轴偏移tx,单位px|-|
+|translateZ|tz| 在Z轴偏移tx,单位px|nvue不支持|
+|translate3d|tx,ty,tz| 在X轴偏移tx,在Y轴偏移ty,在Z轴偏移tz,单位px|nvue不支持|
+
+```javascript
+this.$refs.ani.step({
+ translateX: '100px'
+})
+```
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/transition/transition](https://hellouniapp.dcloud.net.cn/pages/extUI/transition/transition)
\ No newline at end of file