├── .gitignore ├── README.md ├── miniprogram ├── app.js ├── app.json ├── app.wxss ├── component │ ├── NewWxComment │ │ ├── NewWxComment.js │ │ ├── NewWxComment.json │ │ ├── NewWxComment.wxml │ │ ├── NewWxComment.wxs │ │ ├── NewWxComment.wxss │ │ └── images │ │ │ ├── about.png │ │ │ ├── about_active.png │ │ │ ├── copy_link.png │ │ │ ├── copy_link_active.png │ │ │ ├── home.png │ │ │ ├── home_active.png │ │ │ ├── like.png │ │ │ ├── like_active.png │ │ │ ├── more.png │ │ │ ├── more_active.png │ │ │ ├── poster.png │ │ │ ├── poster_active.png │ │ │ ├── reward.png │ │ │ ├── reward_active.png │ │ │ ├── share.png │ │ │ └── share_active.png │ └── WxLogin │ │ ├── WxLogin.js │ │ ├── WxLogin.json │ │ ├── WxLogin.wxml │ │ ├── WxLogin.wxss │ │ └── images │ │ └── login_active.png ├── libs │ ├── leancloud │ │ ├── av-weapp-min.js │ │ └── rest_api_leancloud.js │ └── scripts │ │ └── common.js ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── logs │ │ ├── logs.js │ │ ├── logs.json │ │ ├── logs.wxml │ │ └── logs.wxss ├── sitemap.json └── utils │ └── util.js ├── project.config.json └── screenshots ├── NewWxComment.png └── Xiaobaiai.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.bak 4 | *.bin 5 | *.exe 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NewWxComment 2 | 3 | `NewWxComment`[https://github.com/yicm/NewWxComment](https://github.com/yicm/NewWxComment)是一个微信小程序的评论组件,结合BaaS提供商[LeanCloud](https://leancloud.cn/),无需其他另外的个人或者云服务器,就可以免费使用。解决了需要个人去注册域名、备案、购买云服务器的繁杂问题。且兼容`Valine`[https://github.com/xCss/Valine](https://github.com/xCss/Valine)评论,打通PC端和移动端评论,特别适合使用Valine评论系统且想同时开发小程序文章评论的同学们。 4 | 5 | > ps: 打造这个插件的目的在于本人想要打造一个类似hexo通用博客框架,且是一个移动端的框架,首先采用微信小程序实现,现已完成博文编译器的开发,评论插件的开发(打通PC端Valine插件),微信小程序的经典主题开发(未发布),期待发布经典主题后,有更多开发者加入,开发更多的插件和主题,一起打通PC端和"现在移动端",实现移动端的个人博客; 6 | 7 | > Hexo博客编译器已开源[https://github.com/yicm/HMP](https://github.com/yicm/HMP),直接打通静态博客和微信小程序,Demo可微信搜索`小白AI博客`查看。 8 | 9 | > 先提前“剧透”下经典主题首页,倾心打造: 10 | 11 | ![image](https://raw.githubusercontent.com/yicm/NewWxComment/master/screenshots/Xiaobaiai.jpg) 12 | 13 | 14 | # 特色 15 | 16 | - 独立插件,独立放入小程序项目即可使用 17 | - 打通Valine评论系统,统一PC端和小程序端 18 | - 友好的UI界面和交互界面 19 | - 与微信用户信息绑定,显示微信用户头像和昵称 20 | - 支持文章阅读量统计功能 21 | - 支持评论回复功能,即子评论 22 | - 支持emoji表情显示😉 23 | - 支持评论分页加载 24 | - 支持评论分页参数设置 25 | - 内置获取微信用户公共信息授权 26 | - 支持light/dark两种主题 27 | - 机型兼容友好,包括全面屏iphone11等 28 | 29 | # 已测试通过机型 30 | 31 | - iphone6s plus 32 | - iphone11/xr 33 | - ipad4 pro 34 | - redmi6 pro 35 | 36 | # 屏幕截图 37 | 38 | 下图为`NewWxComment`嵌入式到具体博客中显示的效果。PC端评论效果可以访问网站[https://xiaobaiai.net](https://xiaobaiai.net) 39 | 40 | ![image](https://raw.githubusercontent.com/yicm/NewWxComment/master/screenshots/NewWxComment.png) 41 | 42 | # 快速入手 43 | 44 | > 注意:下面的前三步也可以参考Valine评论插件方法,如果是Valine已经设置好了,直接跳过前三步; 45 | 46 | 1. 注册LeanCloud账号,并创建过LeanCloud应用; 47 | 48 | 2. 登陆LeanCloud账号,打开链接[https://leancloud.cn/docs/weapp-domains.html](https://leancloud.cn/docs/weapp-domains.html),将显示域名配置到你的微信小程序服务器配置中; 49 | 50 | 3. 设置小程序的 AppID 与 AppSecret 51 | 3.1 登录 微信公众平台,在`设置` > `开发设置` 中获得 AppID 与 AppSecret 52 | 3.2 前往 LeanCloud `控制台` > `组件` > `社交`,保存「微信小程序」的 AppID 与 AppSecret 53 | 54 | 4. 克隆Demo项目NewWxComment(Demo项目已附带NewWxComment组件) 55 | 56 | ``` 57 | $ git clone https://github.com/yicm/NewWxComment.git 58 | ``` 59 | 60 | 5. 将LeanCloud自己的AppID和AppKey复制到NewWxComment.js对应位置; 61 | 62 | ``` 63 | AV.init({ 64 | appId: 'your leancloud appid', 65 | appKey: 'your leancloud appkey', 66 | }); 67 | ``` 68 | 69 | 6. 在小程序index.wxml和index.json文件中已经引入NewWxComment组件 70 | 71 | index.wxml 72 | 73 | ``` 74 | 75 | ``` 76 | 77 | index.json 78 | 79 | ``` 80 | "usingComponents": { 81 | "NewWxComment": "/component/NewWxComment/NewWxComment" 82 | } 83 | ``` 84 | 85 | index.js中添加触底才获取评论数据: 86 | 87 | ``` 88 | // 到底触发获取评论数据函数 89 | // 添加触发拉取评论函数 90 | onReachBottom: function() { 91 | let newWxComment = this.selectComponent('#NewWxComment'); 92 | newWxComment.onReachBottom(); 93 | } 94 | ``` 95 | 如果评论格数显示不正常,检查app.js `container`样式: 96 | 97 | ``` 98 | .container { 99 | padding: 0 24rpx; 100 | background-color: #fff; 101 | font-family: Microsoft YaHei, Helvetica, Arial, sans-serif; 102 | } 103 | ``` 104 | 105 | NewWxComment组件属性说明: 106 | 107 | ```bash 108 | articleTitle: 待评论页文章标题 109 | articleURL: 待评论页文章链接(不包含网站域名) 110 | homeURL: 小程序首页路径 111 | pageSize: 评论每页加载条数,默认值5 112 | contentMinLen: 评论最小长度要求,默认值2 113 | contentMaxLen: 评论最大长度限制,默认值300 114 | articleID: 待评论文章唯一ID 115 | websiteURL: PC端网站域名(若无可不填),默认值`https://xiaobaiai.net` 116 | theme: 主题设置,仅支持 light 或者 dark 两个属性值 117 | ``` 118 | 119 | # Demo 120 | 121 | 小程序`小白AI博客`引用NewWxComment组件示例: 122 | 123 | ![](https://gitee.com/yicm/Images/raw/master/xiaobaiai/news/10004_2.jpg) 124 | 125 | # TODO 126 | 127 | - 支持点赞列表 128 | - 支持作者回复高亮标志 129 | - 支持垃圾评论过滤 130 | - 支持海报分享 131 | - 支持赞赏 132 | - ... 133 | 134 | # License 135 | 136 | [Mulan PSL v1](http://license.coscl.org.cn/MulanPSL) 137 | 138 | 139 | -------------------------------------------------------------------------------- /miniprogram/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }) -------------------------------------------------------------------------------- /miniprogram/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/logs/logs" 5 | ], 6 | "window": { 7 | "backgroundTextStyle": "light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "WeChat", 10 | "navigationBarTextStyle": "black" 11 | }, 12 | "sitemapLocation": "sitemap.json" 13 | } -------------------------------------------------------------------------------- /miniprogram/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | 3 | .container { 4 | padding: 0 24rpx; 5 | background-color: #fff; 6 | font-family: Microsoft YaHei, Helvetica, Arial, sans-serif; 7 | } 8 | -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/NewWxComment.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) [2019] [Ethan(yicm1102@gmail.com)] 3 | [NewWxComment] is licensed under the Mulan PSL v1. 4 | You can use this software according to the terms and conditions of the Mulan PSL v1. 5 | You may obtain a copy of Mulan PSL v1 at: 6 | http://license.coscl.org.cn/MulanPSL 7 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR 8 | IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR 9 | PURPOSE. 10 | See the Mulan PSL v1 for more details. 11 | 12 | And more: 13 | author: yicm1102@gmail.com 14 | github: https://github.com/yicm/NewWxComment 15 | website: https://xiaobaiai.net 16 | sync valine version: 1.3.6 17 | leanstorage javascript api: https://leancloud.cn/docs/leanstorage_guide-js.html 18 | */ 19 | const AV = require('../../libs/leancloud/av-weapp-min.js'); 20 | var Common = require('../../libs/scripts/common.js'); 21 | // LeanCloud 应用的 ID 和 Key 22 | 23 | AV.init({ 24 | appId: 'your leancloud app id', 25 | appKey: 'your leancloud app key', 26 | }); 27 | 28 | Component({ 29 | /** 30 | * 组件的属性列表 31 | */ 32 | properties: { 33 | articleTitle: { 34 | type: String, 35 | value: '' 36 | }, 37 | articleURL: { 38 | type: String, 39 | value: '' 40 | }, 41 | homeURL: { 42 | type: String, 43 | value: '../index/index' 44 | }, 45 | pageSize: { 46 | type: Number, 47 | value: 5 48 | }, 49 | theme: { 50 | type: String, 51 | value: 'light' // light & dark 52 | }, 53 | contentMinLen: { 54 | // 评论内容至少为多长限制 55 | type: Number, 56 | value: 2 57 | }, 58 | contentMaxLen: { 59 | type: Number, 60 | value: 300 61 | }, 62 | copyRight: { 63 | type: String, 64 | value: '©2019 小白AI.易名 xiaobaiai.net' 65 | }, 66 | articleID: { 67 | type: String, 68 | value: '', 69 | observer: function (newVal, oldVal) { 70 | let that = this; 71 | // console.log(that.data.articleID); 72 | // console.log(newVal); 73 | // 在组件实例进入页面节点树时执行 74 | // this.data生效 75 | // 获取总评论数 76 | this._leanQuery('total'); 77 | // 获取点赞数 78 | // TODO 79 | 80 | if (this.data.theme == 'dark') { 81 | this.setData({ 82 | isDark: true 83 | }) 84 | } else { 85 | this.setData({ 86 | isDark: false 87 | }) 88 | } 89 | this.fetechPCommentNum(); 90 | } 91 | }, 92 | websiteURL: { 93 | type: String, 94 | value: 'https://xiaobaiai.net' 95 | } 96 | }, 97 | 98 | /** 99 | * 组件的初始数据 100 | */ 101 | data: { 102 | // 主题 103 | isDark: false, 104 | // 系统相关 105 | uaInfo: '', 106 | // 赞赏码 107 | praiseQRCodeURL: 'https://gitee.com/yicm/Images/raw/master/common/wx_appreciation_code.jpg', 108 | // 授权相关 109 | showAurButton: false, 110 | isMenuboxShow: false, 111 | isMenuboxLoad: true, 112 | enableComment: true, 113 | menuBackgroup: false, 114 | isLoginPopup: false, 115 | userInfo: {}, 116 | // 评论相关 117 | commentTabName: 'Comment', 118 | counterTabName: 'Counter', 119 | placeholder: '评论...', 120 | display: 'block', 121 | commentPNum: 0, 122 | commentCount: 0, 123 | likeCount: 0, 124 | commentCountStr: '', 125 | commentIndex: 1, 126 | isLastPage: false, 127 | isLoading: false, 128 | isFocusing: false, 129 | commentsRawList: [], 130 | commentsList: [], 131 | content: '', 132 | toCommentPid: undefined, 133 | toCommentRid: undefined 134 | }, 135 | 136 | /** 137 | * 组件生命周期函数 138 | */ 139 | lifetimes: { 140 | created: function () { 141 | // 组件实例刚刚被创建时 142 | console.log("created"); 143 | }, 144 | attached: function () { 145 | this.getUAInfo(); 146 | }, 147 | ready: function () { 148 | // 在组件在视图层布局完成后执行 149 | //console.log("ready"); 150 | }, 151 | detached: function () { 152 | // 在组件实例被从页面节点树移除时执行 153 | //console.log("detached"); 154 | }, 155 | }, 156 | /** 157 | * 组件的方法列表 158 | */ 159 | methods: { 160 | showHideMenu: function (e) { 161 | this.setData({ 162 | showAurButton: false, 163 | isMenuboxShow: !this.data.isMenuboxShow, 164 | isMenuboxLoad: false, 165 | menuBackgroup: this.data.isMenuboxShow 166 | }) 167 | }, 168 | // 点击非评论区隐藏功能菜单 169 | hiddenMenubox: function () { 170 | console.log("hiddenMenubox"); 171 | this.setData({ 172 | isMenuboxShow: false, 173 | menuBackgroup: false 174 | }) 175 | }, 176 | goHome: function () { 177 | var that = this; 178 | wx.switchTab({ 179 | url: that.data.homeURL 180 | }) 181 | }, 182 | onCreatePoster: function () { 183 | wx.showToast({ 184 | title: '敬请期待', 185 | icon: 'none', 186 | duration: 2000 187 | }); 188 | }, 189 | clickLike: function () { 190 | wx.showToast({ 191 | title: '敬请期待', 192 | icon: 'none', 193 | duration: 2000 194 | }); 195 | }, 196 | aboutWxComment: function () { 197 | let that = this; 198 | wx.showModal({ 199 | title: '关于', 200 | content: that.data.websiteURL, 201 | showCancel: false, 202 | confirmText: '记住了', 203 | success(res) { 204 | // nothing to do 205 | } 206 | }) 207 | }, 208 | praise: function () { 209 | let that = this; 210 | wx.previewImage({ 211 | urls: [that.data.praiseQRCodeURL], 212 | current: that.data.praiseQRCodeURL 213 | }) 214 | }, 215 | copyLink: function () { 216 | let that = this; 217 | if (that.data.websiteURL) { 218 | console.log(that.data.websiteURL + that.data.articleURL); 219 | wx.setClipboardData({ 220 | data: that.data.websiteURL + that.data.articleURL, 221 | success: function (res) { 222 | wx.showToast({ 223 | title: '复制成功', 224 | icon: 'success', 225 | duration: 2000 226 | }); 227 | } 228 | }); 229 | } else { 230 | console.log('网站主页域名未设置'); 231 | } 232 | }, 233 | replay: function (e) { 234 | let that = this; 235 | let id = e.target.dataset.id; 236 | let name = e.target.dataset.name; 237 | let rid = e.target.dataset.rid; 238 | let pid = e.target.dataset.pid; 239 | let commentdate = e.target.dataset.commentdate; 240 | if (id) { 241 | that.data.isFocusing = true; 242 | if (that.data.enableComment) { 243 | that.setData({ 244 | toCommentPid: id, 245 | placeholder: "@" + name, 246 | focus: true, 247 | toCommentRid: rid || id, 248 | toUser: name, 249 | commentdate: commentdate 250 | }); 251 | 252 | } 253 | } else { 254 | console.log('暂不支持更多嵌套层评论'); 255 | } 256 | //console.log('toCommentPid', that.data.toCommentPid); 257 | //console.log('toCommentRid', that.data.toCommentRid); 258 | }, 259 | onReplyBlur: function (e) { 260 | let that = this; 261 | console.log('onReplyBlur'); 262 | that.data.isFocusing = false; 263 | const text = e.detail.value.trim(); 264 | if (text === '') { 265 | that._resetInput(); 266 | } 267 | }, 268 | onRepleyFocus: function (e) { 269 | console.log('onReplyFocus'); 270 | }, 271 | getLeanCloudACL: function (read, write) { 272 | let acl = new AV.ACL(); 273 | acl.setPublicReadAccess(read); 274 | acl.setPublicWriteAccess(write); 275 | return acl; 276 | }, 277 | writeComment: function (content, rid, pid, is_reply, to_user, user_info) { 278 | let that = this; 279 | // 未存在会创建新表 280 | let Ct = AV.Object.extend(that.data.commentTabName); 281 | let commenter = new Ct(); 282 | let commentObj = {}; 283 | let currentDate = new Date(); 284 | console.log('writeComment' + that.data.articleID); 285 | commentObj["nick"] = that.data.userInfo.nickName; 286 | commentObj["mail"] = ''; 287 | commentObj["child"] = [] 288 | commentObj['link'] = ''; 289 | commentObj["url"] = that.data.articleURL; 290 | commentObj['avatar'] = that.data.userInfo.avatarUrl; 291 | commentObj['comment'] = content; 292 | 293 | commenter.set('nick', that.data.userInfo.nickName); 294 | commenter.set('mail', ''); 295 | commenter.set('link', ''); 296 | commenter.set('ua', that.data.uaInfo); 297 | commenter.set('url', that.data.articleURL); 298 | commenter.set('comment', `

${content}

`); 299 | commenter.set('insertedAt', currentDate); 300 | if (is_reply) { 301 | commentObj["pid"] = pid; 302 | commentObj["rid"] = rid; 303 | commenter.set('rid', rid); 304 | commenter.set('pid', pid); 305 | commenter.set('comment', `

@${to_user} , ${content}

`); 306 | } 307 | commenter.setACL(that.getLeanCloudACL(true, false)); 308 | const user = AV.User.current(); 309 | let targetUser = AV.Object.createWithoutData('_User', user.id); 310 | commenter.set('targetUser', targetUser); 311 | 312 | commenter.save().then(ret => { 313 | if (!is_reply) { 314 | that.setData({ 315 | commentPNum: that.data.commentPNum + 1, 316 | commentCountStr: "有" + (that.data.commentCount + 1) + "条评论", 317 | commentCount: that.data.commentCount + 1 318 | }) 319 | } else { 320 | that.setData({ 321 | commentCountStr: "有" + (that.data.commentCount + 1) + "条评论", 322 | commentCount: that.data.commentCount + 1 323 | }) 324 | } 325 | 326 | let buildArray = new Array(); 327 | buildArray[0] = ret; 328 | console.log(buildArray); 329 | // 子评论需要对已加载评论重新进行评论树构建 330 | if (is_reply) { 331 | that.buildCommentTree(buildArray, true, true); 332 | } else { 333 | that.buildCommentTree(buildArray, true); 334 | } 335 | }).catch(ex => { 336 | wx.showToast({ 337 | title: '评论发生错误...', 338 | icon: 'none', 339 | duration: 2000 340 | }) 341 | console.log(ex.code); 342 | console.log(ex.message); 343 | console.log(ex.error); 344 | }); 345 | }, 346 | // 提交评论 347 | bindFormSubmit: function (e) { 348 | let that = this; 349 | // 判断内容长度是否满足最小要求 350 | let content = e.detail.value.inputComment; 351 | if (content.length <= that.data.contentMinLen) { 352 | wx.showToast({ 353 | title: '评论内容长度不够^_^', 354 | icon: 'none', 355 | duration: 2000 356 | }) 357 | return; 358 | } 359 | 360 | // 检查授权 & 写入评论 361 | wx.getSetting({ 362 | success(res) { 363 | if (!res.authSetting['scope.userInfo']) { 364 | // console.log("没有授权获取用户信息"); 365 | that.setData({ 366 | showAurButton: true 367 | }); 368 | } else { 369 | // console.log("已经授权获取用户信息,开始获取信息"); 370 | wx.getUserInfo({ 371 | success: function (res) { 372 | that.data.userInfo = res.userInfo; 373 | // LeanCloud 用户一键登录 374 | AV.User.loginWithWeapp().then(user => { 375 | if (user.attributes.nickName != 376 | that.data.userInfo.nickName || 377 | user.attributes.avatarUrl != 378 | that.data.userInfo.avatarUrl) { 379 | // 更新LeanCloud用户信息 380 | console.log('更新LeanCloud用户信息'); 381 | that._updateUserInfoInLeanCloud(); 382 | } 383 | let is_reply = false; 384 | let rid = that.data.toCommentRid; 385 | let pid = that.data.toCommentPid; 386 | let to_user = that.data.toUser; 387 | let user_info = that.data.userInfo; 388 | if (rid || pid) { 389 | is_reply = true; 390 | } 391 | // 写入评论 392 | that.writeComment(content, rid, pid, is_reply, to_user, user_info); 393 | }).catch(console.error); 394 | } 395 | }) 396 | } 397 | }, 398 | fail: function () { 399 | console.log("获取用户的当前设置失败"); 400 | } 401 | }) 402 | 403 | }, 404 | onReachBottom: function () { 405 | console.log("达到底部"); 406 | let that = this; 407 | //console.log(that.data.commentPNum); 408 | //console.log(that.data.isLastPage); 409 | if (that.data.commentPNum > 0 && !that.data.isLastPage) { 410 | that.fetchCommentDetailData(that.data.commentIndex); 411 | let current_pcomment_showed_num = that.data.commentIndex * that.data.pageSize; 412 | if (current_pcomment_showed_num < that.data.commentPNum) { 413 | that.data.commentIndex = that.data.commentIndex + 1; 414 | } else { 415 | that.setData({ 416 | isLastPage: true 417 | }); 418 | } 419 | } 420 | }, 421 | checkTime: function (s) { 422 | return s < 10 ? '0' + s : s; 423 | }, 424 | getLocalDateTimeStr: function (input) { 425 | let that = this; 426 | let d = new Date(input) 427 | let res_date = d.getFullYear() + '-' + that.checkTime((d.getMonth() + 1)) + '-' + that.checkTime(d.getDate()); 428 | let res_time = that.checkTime(d.getHours()) + ':' + that.checkTime(d.getMinutes()) + ':' + that.checkTime(d.getSeconds()); 429 | return res_date + ' ' + res_time; 430 | }, 431 | buildCommentTree: function (source, is_wechat = false, is_reply = false, p_key = 'pid', self_key = 'id', child_key = 'child', root_value = undefined) { 432 | let that = this; 433 | // 整理数据 434 | let new_data = []; 435 | for (let i = 0; i < source.length; i++) { 436 | let item = {}; 437 | item["id"] = source[i].id; 438 | item["author_name"] = source[i].attributes.nick; 439 | item["content"] = source[i].attributes.comment; 440 | item["date"] = that.getLocalDateTimeStr(source[i].updatedAt); 441 | item["child"] = [] 442 | item["pid"] = source[i].attributes.pid; 443 | item["rid"] = source[i].attributes.rid; 444 | item["url"] = source[i].attributes.url; 445 | // 处理小程序提交评论 446 | if (source[i].attributes.targetUser) { 447 | if (is_wechat && !source[i].attributes.targetUser.attributes.nickName) { 448 | item['avatar'] = that.data.userInfo.avatarUrl; 449 | } else { 450 | item['author_name'] = source[i].attributes.targetUser.attributes.nickName; 451 | item['avatar'] = source[i].attributes.targetUser.attributes.avatarUrl; 452 | } 453 | 454 | } 455 | // 正则处理valine评论内容 456 | if (!item["pid"]) { 457 | item["content"] = item["content"].match(/

(.*)<\/p>/)[1]; 458 | 459 | } else { 460 | item["content"] = item["content"].match(/<\/a> , (.*)<\/p>/)[1]; 461 | } 462 | 463 | new_data.push(item); 464 | } 465 | // 记录所有原始数据 466 | if (new_data) { 467 | that.data.commentsRawList = [].concat(that.data.commentsRawList, new_data); 468 | //console.log(that.data.commentsRawList); 469 | } 470 | if (is_wechat && is_reply) { 471 | new_data = that.data.commentsRawList; 472 | } 473 | 474 | // 生成评论树 475 | let data = JSON.parse(JSON.stringify(new_data)); 476 | for (let i = 0; i < data.length; i++) { 477 | let item_i = data[i]; 478 | if (item_i[p_key] === root_value) { 479 | continue; 480 | } 481 | for (let j = 0; j < data.length; j++) { 482 | if (i === j) { 483 | continue; 484 | } 485 | let item_j = data[j]; 486 | if (item_i[p_key] === item_j[self_key]) { 487 | if (!item_j[child_key] || 488 | Object.prototype.toString.call(item_j[child_key]) !== 489 | '[object Array]' 490 | ) { 491 | item_j[child_key] = []; 492 | } 493 | item_j[child_key].push(item_i); 494 | break; 495 | } 496 | } 497 | } 498 | let tree_data = data.filter(item => item[p_key] === root_value); 499 | 500 | // set data 501 | if (tree_data) { 502 | if (is_wechat && !is_reply) { 503 | that.setData({ 504 | commentsList: [].concat(tree_data, that.data.commentsList) 505 | }); 506 | } else if (is_wechat && is_reply) { 507 | that.setData({ 508 | commentsList: tree_data 509 | }) 510 | } else { 511 | that.setData({ 512 | commentsList: [].concat(that.data.commentsList, tree_data) 513 | }); 514 | } 515 | } 516 | // 重置输入框状态 517 | console.log('重置输入框状态'); 518 | that._resetInput(); 519 | }, 520 | fetchCommentDetailData: function (no) { 521 | let that = this; 522 | let cq = that._leanQuery(that.data.articleID); 523 | let size = that.data.pageSize; 524 | let all_data = []; 525 | that.setData({ 526 | isLoading: true 527 | }); 528 | cq.limit(size); 529 | cq.skip((no - 1) * size); 530 | cq.include('targetUser'); 531 | cq.find().then(rets => { 532 | let len = rets.length; 533 | let rids = [] 534 | for (let i = 0; i < len; i++) { 535 | let ret = rets[i]; 536 | rids.push(ret.id) 537 | } 538 | all_data = [].concat(rets); 539 | // load children comment 540 | that._leanQuery(that.data.articleID, rids).find().then(ret => { 541 | let childs = ret || []; 542 | console.log("子评论数:" + childs.length); 543 | all_data = all_data.concat(childs); 544 | //console.log(all_data); 545 | that.buildCommentTree(all_data); 546 | }).catch(ex => { 547 | wx.showToast({ 548 | title: '加载评论错误...', 549 | icon: 'none', 550 | duration: 2000 551 | }) 552 | console.log(ex.code); 553 | console.log(ex.message); 554 | console.log(ex.error); 555 | }) 556 | }).catch(ex => { 557 | wx.showToast({ 558 | title: '加载评论出错...', 559 | icon: 'none', 560 | duration: 2000 561 | }) 562 | console.log(ex.code); 563 | console.log(ex.message); 564 | console.log(ex.error); 565 | }).finally(function () { 566 | that.setData({ 567 | isLoading: false 568 | }); 569 | }); 570 | }, 571 | getUAInfo: function () { 572 | let that = this; 573 | wx.getSystemInfo({ 574 | success: function (res) { 575 | if (res.system.includes('Android')) { 576 | that.data.uaInfo = "Mozilla/5.0 (" + res.model + ";" + res.system + ";" + res.language + ") AppleWebKit/537.36 MicroMessenger/" + res.version; 577 | } else { 578 | let system = res.system.replace(/\./g, '_') + " like Mac OS X"; 579 | that.data.uaInfo = "Mozilla/5.0 (" + res.model + ";" + system + ";" + res.language + ") AppleWebKit/537.36 MicroMessenger/" + res.version; 580 | } 581 | 582 | console.log(that.data.uaInfo); 583 | }, 584 | }) 585 | }, 586 | fetechPCommentNum: function () { 587 | let that = this; 588 | that._leanQuery(that.data.articleID).count().then(num => { 589 | if (num > 0) { 590 | console.log("父评论总数:" + num); 591 | that.data.commentPNum = num; 592 | } else { 593 | console.log("暂无评论"); 594 | that.setData({ 595 | isLastPage: true 596 | }) 597 | } 598 | }).catch(ex => { 599 | // https://leancloud.cn/docs/error_code.html#hash1389221 600 | // first time to create Counter Class 601 | if (101 == error.code) { 602 | // do something 603 | } 604 | console.log(ex.code); 605 | console.log(ex.message); 606 | console.log(ex.error); 607 | }); 608 | }, 609 | // 获取评论总数 610 | fetchCommentCount: function () { 611 | let that = this; 612 | let counter_query = new AV.Query(that.data.commentTabName); 613 | counter_query.equalTo('url', that.data.articleID); 614 | counter_query.count().then(function (count) { 615 | console.log('评论总数:' + count); 616 | if (count && count > 0) { 617 | that.setData({ 618 | commentCountStr: "有" + count + "条评论", 619 | commentCount: count 620 | }); 621 | } 622 | // 更新页面计数和评论数及点赞数 623 | that.updatePageCounter(); 624 | }, 625 | function (error) { 626 | console.log(error.message); 627 | console.log(error.code); 628 | // https://leancloud.cn/docs/error_code.html#hash1389221 629 | // first time to create Counter Class 630 | if (101 == error.code) { 631 | // 没有评论表,评论为0 632 | that.setData({ 633 | isLastPage: true, 634 | commentCountStr: "有0条评论" 635 | }); 636 | } 637 | }); 638 | }, 639 | createPageCounter: function () { 640 | let that = this; 641 | // 未存在会创建新表 642 | let Counter = AV.Object.extend(that.data.counterTabName); 643 | let newCounter = new Counter(); 644 | newCounter.setACL(that.getLeanCloudACL(true, true)); 645 | newCounter.set('url', that.data.articleID); 646 | newCounter.set('xid', that.data.articleID); 647 | newCounter.set('title', that.data.articleTitle); 648 | newCounter.set('time', 1); 649 | newCounter.set('comments', that.data.commentCount); 650 | newCounter.set('likes', that.data.likeCount); 651 | newCounter.save().then(ret => { 652 | // nothing to do 653 | console.log('初始化页面计数表成功'); 654 | }).catch(ex => { 655 | console.log(ex) 656 | wx.showToast({ 657 | title: '创建数据表失败', 658 | icon: 'none', 659 | duration: 2000 660 | }); 661 | }); 662 | }, 663 | updatePageCounter: function () { 664 | let that = this; 665 | let query = new AV.Query(that.data.counterTabName); 666 | query.equalTo('url', that.data.articleID); 667 | query.find().then(ret => { 668 | //console.log(ret); 669 | if (ret.length > 0) { 670 | let v = ret[0]; 671 | v.increment("time"); 672 | v.set('comments', that.data.commentCount); 673 | v.set('likes', that.data.likeCount); 674 | v.save().then(rt => { 675 | // 页面计数更新成功 676 | console.log('页面计数更新成功'); 677 | }).catch(ex => { 678 | console.log(ex) 679 | // 页面计数更新失败 680 | console.log('页面计数更新失败'); 681 | }); 682 | } else { 683 | // 小程序端先于PC端访问,则需要创建该条记录 684 | let Counter = AV.Object.extend(that.data.counterTabName); 685 | let counter = new Counter(); 686 | counter.setACL(that.getLeanCloudACL(true, true)); 687 | counter.set('url', that.data.articleID); 688 | counter.set('xid', that.data.articleID); 689 | counter.set('title', that.data.articleTitle); 690 | counter.set('time', 1); 691 | counter.set('comments', that.data.commentCount); 692 | counter.set('likes', that.data.likeCount); 693 | 694 | counter.save(); 695 | } 696 | }).catch(ex => { 697 | console.log(ex.message); 698 | console.log(ex.code); 699 | if (ex.code == 101) { 700 | console.log('页面计数表未存在,开始创建'); 701 | that.createPageCounter(); 702 | } 703 | }); 704 | }, 705 | _resetInput: function () { 706 | let that = this; 707 | that.setData({ 708 | toCommentPid: '', 709 | placeholder: "评论...", 710 | toCommentRid: '', 711 | commentdate: "", 712 | content: '', 713 | toUser: '' 714 | }); 715 | }, 716 | _leanQuery: function (k) { 717 | let that = this; 718 | let len = arguments.length; 719 | if (k === 'total') { 720 | that.fetchCommentCount(); 721 | } else if (len == 1) { 722 | let notExist = new AV.Query(that.data.commentTabName); 723 | notExist.doesNotExist('rid'); 724 | let isEmpty = new AV.Query(that.data.commentTabName); 725 | isEmpty.equalTo('rid', ''); 726 | let q = AV.Query.or(notExist, isEmpty); 727 | if (k === '*') { 728 | q.exists('url'); 729 | } else { 730 | q.equalTo('url', decodeURI(k)); 731 | } 732 | q.addDescending('createdAt'); 733 | q.addDescending('insertedAt'); 734 | return q; 735 | } else { 736 | let query = new AV.Query(that.data.commentTabName); 737 | query.containedIn('rid', arguments[1]); 738 | query.addDescending('createdAt'); 739 | query.addDescending('insertedAt'); 740 | query.include('targetUser'); 741 | return query; 742 | } 743 | }, 744 | _updateUserInfoInLeanCloud: function () { 745 | // 获得当前登录用户 746 | let that = this; 747 | const user = AV.User.current(); 748 | // 调用小程序 API,得到用户信息 749 | wx.getUserInfo({ 750 | success: ({ 751 | userInfo 752 | }) => { 753 | // 更新当前用户的信息 754 | user.set(userInfo).save().then(user => { 755 | // 成功,此时可在控制台中看到更新后的用户信息 756 | //this.data.login_user_info = user.toJSON(); 757 | console.log(user); 758 | }).catch(console.error); 759 | }, 760 | fail: function () { 761 | console.log("获取用户信息失败"); 762 | } 763 | }); 764 | } 765 | } // end of method 766 | }) -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/NewWxComment.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": { 4 | "WxLogin": "/component/WxLogin/WxLogin" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/NewWxComment.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 评论交流 {{enableComment?'(点击评论内容可以回复)':''}} 14 | 15 | 16 | 17 | {{commentCountStr}} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | {{item.author_name}} 35 | {{item.date}} 36 | 37 | 38 | {{item.content}} 39 | 40 | 41 | 42 | 43 | {{item1.author_name}} 回复 {{item.author_name}}: {{item1.content}} 44 | 45 | 46 | 47 | 48 | 49 | 50 | {{item2.author_name}} 回复 {{item1.author_name}}: {{item2.content}} 51 | 52 | 53 | 54 | 55 | 56 | {{item3.author_name}} 回复 {{item2.author_name}}: {{item3.content}} 57 | 58 | 59 | 60 | 61 | 62 | {{item4.author_name}} 回复 {{item3.author_name}}: {{item4.content}} 63 | 64 | 65 | 66 | 67 | 68 | {{item5.author_name}} 回复 {{item4.author_name}}: {{item5.content}} 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ---我是有底线的--- 97 | 98 | 99 | 100 | 101 | 102 | 103 | {{copyRight}} 104 | 105 | 106 | 107 | 108 | 109 | 110 |

111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 转发 128 | 129 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 海报 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 关于 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 点赞 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 鼓励 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 链接 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 |
181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/NewWxComment.wxs: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 17 | 18 | /* 19 | * These are the functions you'll usually want to call 20 | * They take string arguments and return either hex or base-64 encoded strings 21 | */ 22 | function hex_md5(s) { return binl2hex(core_md5(str2binl(s), s.length * chrsz)); } 23 | 24 | /* 25 | * Perform a simple self-test to see if the VM is working 26 | */ 27 | function md5_vm_test() { 28 | return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; 29 | } 30 | 31 | /* 32 | * Calculate the MD5 of an array of little-endian words, and a bit length 33 | */ 34 | function core_md5(x, len) { 35 | /* append padding */ 36 | x[len >> 5] |= 128 << ((len) % 32); 37 | x[(((len + 64) >>> 9) << 4) + 14] = len; 38 | 39 | var a = 1732584193; 40 | var b = -271733879; 41 | var c = -1732584194; 42 | var d = 271733878; 43 | 44 | for (var i = 0; i < x.length; i += 16) { 45 | var olda = a; 46 | var oldb = b; 47 | var oldc = c; 48 | var oldd = d; 49 | 50 | a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); 51 | d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); 52 | c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); 53 | b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); 54 | a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); 55 | d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); 56 | c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); 57 | b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); 58 | a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); 59 | d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); 60 | c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); 61 | b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); 62 | a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); 63 | d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); 64 | c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); 65 | b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); 66 | 67 | a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); 68 | d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); 69 | c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); 70 | b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); 71 | a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); 72 | d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); 73 | c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); 74 | b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); 75 | a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); 76 | d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); 77 | c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); 78 | b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); 79 | a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); 80 | d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); 81 | c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); 82 | b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); 83 | 84 | a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); 85 | d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); 86 | c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); 87 | b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); 88 | a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); 89 | d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); 90 | c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); 91 | b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); 92 | a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); 93 | d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); 94 | c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); 95 | b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); 96 | a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); 97 | d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); 98 | c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); 99 | b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); 100 | 101 | a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); 102 | d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); 103 | c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); 104 | b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); 105 | a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); 106 | d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); 107 | c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); 108 | b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); 109 | a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); 110 | d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); 111 | c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); 112 | b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); 113 | a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); 114 | d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); 115 | c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); 116 | b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); 117 | 118 | a = safe_add(a, olda); 119 | b = safe_add(b, oldb); 120 | c = safe_add(c, oldc); 121 | d = safe_add(d, oldd); 122 | } 123 | return [a, b, c, d]; 124 | 125 | } 126 | 127 | /* 128 | * These functions implement the four basic operations the algorithm uses. 129 | */ 130 | function md5_cmn(q, a, b, x, s, t) { 131 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); 132 | } 133 | function md5_ff(a, b, c, d, x, s, t) { 134 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 135 | } 136 | function md5_gg(a, b, c, d, x, s, t) { 137 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 138 | } 139 | function md5_hh(a, b, c, d, x, s, t) { 140 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 141 | } 142 | function md5_ii(a, b, c, d, x, s, t) { 143 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 144 | } 145 | 146 | /* 147 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 148 | * to work around bugs in some JS interpreters. 149 | */ 150 | function safe_add(x, y) { 151 | var lsw = (x & 65535) + (y & 65535); 152 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 153 | return (msw << 16) | (lsw & 65535); 154 | } 155 | 156 | /* 157 | * Bitwise rotate a 32-bit number to the left. 158 | */ 159 | function bit_rol(num, cnt) { 160 | return (num << cnt) | (num >>> (32 - cnt)); 161 | } 162 | 163 | /* 164 | * Convert a string to an array of little-endian words 165 | * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. 166 | */ 167 | function str2binl(str) { 168 | var bin = []; 169 | var mask = (1 << chrsz) - 1; 170 | for (var i = 0; i < str.length * chrsz; i += chrsz) 171 | bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32); 172 | return bin; 173 | } 174 | 175 | 176 | /* 177 | * Convert an array of little-endian words to a hex string. 178 | */ 179 | function binl2hex(binarray) { 180 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 181 | var str = ""; 182 | for (var i = 0; i < binarray.length * 4; i++) { 183 | str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 15) + 184 | hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 15); 185 | } 186 | return str; 187 | } 188 | 189 | module.exports = { 190 | hexMD5: hex_md5 191 | } -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/NewWxComment.wxss: -------------------------------------------------------------------------------- 1 | /* component/NewWxComment/NewWxComment.wxss */ 2 | 3 | .dark { 4 | background: #000; 5 | color: #fff; 6 | } 7 | 8 | .light { 9 | background: #fff; 10 | background-color: #fff; 11 | color: #484848; 12 | } 13 | 14 | .hide { 15 | display: none; 16 | } 17 | 18 | .show { 19 | display: block; 20 | } 21 | 22 | view { 23 | word-break: break-all; 24 | /* overflow: auto; */ 25 | } 26 | 27 | view { 28 | display: block; 29 | } 30 | 31 | .show-hide-view { 32 | margin: 0rpx, 0rpx, 0rpx, 0rpx; 33 | padding: 0rpx, 0rpx, 0rpx, 0rpx; 34 | border: 1rpx; 35 | } 36 | 37 | .content-article-detail { 38 | border-bottom: 1px solid #eee; 39 | margin-top: 40rpx; 40 | margin-bottom: 24px; 41 | } 42 | 43 | .entry-title { 44 | font-size: 48rpx; 45 | line-height: 1.6; 46 | font-weight: bold; 47 | outline: none; 48 | color: #3a4040; 49 | margin-bottom: 24rpx; 50 | } 51 | 52 | .entry-gap-like { 53 | width: 120rpx; 54 | height: 2px; 55 | background-color: #4c4c4c; 56 | margin-bottom: 32rpx; 57 | } 58 | 59 | .entry-gap-zan { 60 | width: 70rpx; 61 | height: 2px; 62 | background-color: #4c4c4c; 63 | margin-bottom: 32rpx; 64 | } 65 | 66 | .entry-summary { 67 | font-size: 32rpx; 68 | line-height: 64rpx; 69 | letter-spacing: 1px; 70 | } 71 | 72 | .entry-summary image { 73 | width: 100% !important; 74 | } 75 | 76 | .entry-date { 77 | font-size: 24rpx; 78 | line-height: 1.6; 79 | color: #959595; 80 | font-weight: normal; 81 | outline: none; 82 | margin-bottom: 30rpx; 83 | border-bottom: 1px solid #eee; 84 | /* border-bottom: 1px solid #ededed; *//* margin-left: 30rpx; */ 85 | } 86 | 87 | .entry-date-text { 88 | margin-left: 10rpx; 89 | } 90 | 91 | .entry-icon-text { 92 | margin-left: 10rpx; 93 | } 94 | 95 | .entry-category-text { 96 | margin-left: 20rpx; 97 | } 98 | 99 | /* comment */ 100 | 101 | .commentheader { 102 | padding: 20rpx 0; 103 | text-align: left; 104 | font-weight: normal; 105 | font-size: 28rpx; 106 | line-height: 40rpx; 107 | color: #959595; 108 | } 109 | 110 | .commentheader1 { 111 | padding: 5rpx 0; 112 | text-align: left; 113 | font-weight: normal; 114 | font-size: 24rpx; 115 | line-height: 10rpx; 116 | color: red; 117 | } 118 | 119 | .comment { 120 | /* border-bottom: 8px solid #fff; */ 121 | /* background-color: #f5f7f7; */ 122 | padding: 0 24rpx; 123 | border-radius: 8px; 124 | margin: 8px 0; 125 | } 126 | 127 | .comment-bg { 128 | background-color: #f5f7f7; 129 | } 130 | 131 | .comment-children { 132 | border-top: 1px solid #eee; 133 | margin-left: 40rpx; 134 | } 135 | 136 | .comment-user { 137 | display: flex; 138 | align-items: center; 139 | /* height: 80rpx; */ 140 | font-size: 28rpx; 141 | /* line-height: 80rpx; */ 142 | font-weight: normal; 143 | outline: none; 144 | color: #959595; 145 | margin: 10rpx 0; 146 | padding-top: 10rpx; 147 | } 148 | 149 | .replay-user { 150 | display: flex; 151 | align-items: center; 152 | /* height: 80rpx; */ 153 | font-size: 26rpx; 154 | /* line-height: 80rpx; */ 155 | font-weight: normal; 156 | outline: none; 157 | color: #959595; 158 | margin: 10rpx 0; 159 | margin-left: 60rpx; 160 | } 161 | 162 | .comment-user image { 163 | margin-right: 16rpx; 164 | } 165 | 166 | .comment-date { 167 | font-size: 25rpx; 168 | line-height: 1.2; 169 | font-weight: normal; 170 | outline: none; 171 | margin-bottom: 30rpx; 172 | color: #959595; 173 | } 174 | 175 | .comment-response { 176 | color: #4c4c4c; 177 | font-size: 30rpx; 178 | line-height: 1.6rem; 179 | margin-bottom: 50rpx; 180 | } 181 | 182 | .comment-summary { 183 | color: #4c4c4c; 184 | font-size: 28rpx; 185 | line-height: 2rem; 186 | margin-bottom: 10rpx; 187 | margin-left: 60rpx; 188 | } 189 | 190 | .comment-repaly { 191 | color: #757575; 192 | font-size: 30rpx; 193 | line-height: 1.6rem; 194 | margin-bottom: 10rpx; 195 | } 196 | 197 | .comment-post { 198 | color: #757575; 199 | font-size: 30rpx; 200 | line-height: 1.6rem; 201 | margin-bottom: 50rpx; 202 | text-align: center; 203 | display: flex; 204 | flex-direction: row; 205 | } 206 | 207 | .comment-respond { 208 | margin-top: 10rpx; 209 | } 210 | 211 | .comment-reply-title { 212 | font-size: 40rpx; 213 | line-height: 1.5; 214 | color: #21759b; 215 | } 216 | 217 | .comment-fixed { 218 | position: fixed; 219 | bottom: 0; 220 | left: 0; 221 | right: 0; 222 | box-shadow: 0 0 6px rgba(30, 20, 20, 0.1); 223 | z-index: 105; 224 | /*margin-bottom:2rpx; */ 225 | } 226 | 227 | .comment-box { 228 | padding: 16rpx 4rpx; 229 | display: flex; 230 | justify-content: center; 231 | } 232 | 233 | .comment-area { 234 | border: 1px solid #ccc; 235 | margin-top: 20rpx; 236 | max-width: 800rpx; 237 | } 238 | 239 | .comment-button { 240 | width: 160rpx; 241 | display: flex !important; 242 | flex-direction: column; 243 | justify-content: center; 244 | margin-right: 22rpx; 245 | border-bottom-left-radius: 0; 246 | border-top-left-radius: 0; 247 | border-top-right-radius: 6px !important; 248 | border-bottom-right-radius: 6px !important; 249 | text-align: center; 250 | padding: 0 2px !important; 251 | font-size: 16px; 252 | height: 70rpx; 253 | /* border: none; 254 | border-radius: 0; */ 255 | } 256 | 257 | .comment-button::after { 258 | border: none; 259 | } 260 | 261 | .replay-button { 262 | width: 160rpx; 263 | display: flex !important; 264 | flex-direction: column; 265 | justify-content: center; 266 | margin-right: 0rpx; 267 | text-align: center; 268 | padding: 0px !important; 269 | font-size: 12px; 270 | border-radius: 40rpx; 271 | } 272 | 273 | .replay-button::after { 274 | border: none; 275 | } 276 | 277 | .comment-input { 278 | padding: 2px 3px 2px 10px; 279 | font-size: 16px; 280 | width: 51%; 281 | height: 70rpx; 282 | text-align: left; 283 | /* border: 1px solid #296fd0; */ 284 | border-bottom-left-radius: 6px; 285 | border-top-left-radius: 6px; 286 | border-top-right-radius: 0; 287 | border-bottom-right-radius: 0; 288 | } 289 | 290 | .textNoEmpty { 291 | color: red; 292 | } 293 | 294 | .gravatarImg { 295 | /* margin-top: 4px; *//* border-radius: 50%; *//* 296 | opacity: 1; 297 | transform: scale(1); 298 | perspective-origin: top center; 299 | transition: all ease-in-out 0.3s; 300 | */ 301 | height: 48rpx; 302 | width: 48rpx; 303 | } 304 | 305 | .more-comment { 306 | font-size: 30rpx; 307 | line-height: 1.8rem; 308 | margin-bottom: 50rpx; 309 | text-align: center; 310 | margin-top: 20rpx; 311 | } 312 | 313 | .img-plus { 314 | width: 48rpx !important; 315 | height: 48rpx !important; 316 | margin-right: 10px; 317 | margin-top: 10rpx; 318 | } 319 | 320 | /* comment end */ 321 | 322 | .relatedPost { 323 | position: relative; 324 | text-align: left; 325 | margin: 32rpx 0 60rpx; 326 | /* border-bottom: 1px solid #eee; */ 327 | } 328 | 329 | .relatedTitle { 330 | text-align: left; 331 | font-weight: normal; 332 | line-height: 40rpx; 333 | margin-top: 20rpx; 334 | margin-bottom: 20rpx; 335 | font-size: 32rpx; 336 | color: #4c4c4c !important; 337 | } 338 | 339 | .relatedText { 340 | text-align: left; 341 | font-weight: normal; 342 | font-size: 28rpx; 343 | line-height: 60rpx; 344 | color: #4c4c4c !important; 345 | } 346 | 347 | .likePost { 348 | position: relative; 349 | text-align: left; 350 | margin-top: 30rpx; 351 | /* border-bottom: 1px solid #ededed; */ 352 | margin-bottom: 60rpx; 353 | } 354 | 355 | .likeTitle { 356 | text-align: left; 357 | font-weight: normal; 358 | /* line-height: 30rpx; */ 359 | margin-top: 20rpx; 360 | margin-bottom: 20rpx; 361 | /* margin-left: 280rpx; */ 362 | font-size: 28rpx; 363 | color: #959595 !important; 364 | vertical-align: middle; 365 | /* width: 140rpx; 366 | height: 70rpx; *//* border-radius: 35rpx; *//* border: 1rpx solid #c4c4c4; */ 367 | position: absolute; 368 | top: 120rpx; 369 | left: 0; 370 | } 371 | 372 | .likeTitle-img { 373 | position: absolute; 374 | top: 120rpx; 375 | left: 160rpx; 376 | } 377 | 378 | .likeText { 379 | text-align: left; 380 | font-weight: normal; 381 | font-size: 26rpx; 382 | line-height: 30rpx; 383 | color: #0000fe !important; 384 | margin: 140rpx 0 20rpx; 385 | } 386 | 387 | .img-like { 388 | width: 50rpx; 389 | height: 50rpx; 390 | display: inline-block; 391 | text-align: center; 392 | margin-right: 20rpx; 393 | margin-top: 8rpx; 394 | } 395 | 396 | .gravatarLikeImg { 397 | margin-top: 4px; 398 | /*border-radius: 50%; 399 | 400 | opacity: 1; 401 | transform: scale(1); 402 | perspective-origin: top center; 403 | transition: all ease-in-out 0.3s; 404 | */ 405 | height: 48rpx; 406 | width: 48rpx; 407 | margin-right: 20rpx; 408 | } 409 | 410 | .relatedNavigator { 411 | color: #21759b !important; 412 | } 413 | 414 | .sharedetail { 415 | position: relative; 416 | text-align: center; 417 | margin-top: 30rpx; 418 | } 419 | 420 | .share-button { 421 | opacity: 0; 422 | position: absolute; 423 | width: 100%; 424 | height: 100%; 425 | margin: 0; 426 | padding: 0; 427 | top: 0; 428 | left: 0; 429 | } 430 | 431 | .share-title { 432 | color: #333; 433 | font-size: 30rpx; 434 | padding-top: 20rpx; 435 | } 436 | 437 | .copy-button { 438 | color: #296fd0 !important; 439 | } 440 | 441 | .showMessage { 442 | text-align: center; 443 | font-weight: normal; 444 | font-size: 26rpx; 445 | line-height: 40rpx; 446 | color: sandybrown; 447 | margin-top: 20rpx; 448 | margin-bottom: 20rpx; 449 | } 450 | 451 | .no-more { 452 | color: #757575; 453 | font-size: 30rpx; 454 | line-height: 1.8rem; 455 | margin-bottom: 15rpx; 456 | text-align: center; 457 | margin-top: 15rpx; 458 | } 459 | 460 | .ditail-copyright { 461 | font-size: 26rpx; 462 | line-height: 1.2; 463 | font-weight: normal; 464 | text-align: center; 465 | color: #999; 466 | margin-top: 20rpx; 467 | /* margin-bottom: 130rpx; */ 468 | } 469 | 470 | .wxParse-a { 471 | color: #21759b; 472 | } 473 | 474 | .wxParse-code { 475 | padding: 2px 4px !important; 476 | font-size: 90% !important; 477 | border-radius: 3px !important; 478 | color: #eb2226 !important; 479 | background-color: #f9f2f4 !important; 480 | font-family: Source Code Pro, Consolas, Menlo, Monaco, Courier New, monospace !important; 481 | } 482 | 483 | /* menu-box */ 484 | 485 | .menu-box { 486 | position: relative; 487 | height: 90px; 488 | padding: 0px 0 8 0; 489 | box-sizing: border-box; 490 | margin-bottom: -90px; 491 | } 492 | 493 | .menuBackground { 494 | position: fixed; 495 | top: 0; 496 | left: 0; 497 | bottom: 0; 498 | right: 0; 499 | /* background-color: transparent; */ 500 | z-index: 105; 501 | } 502 | 503 | .iconList { 504 | text-align: center; 505 | border-top: 1px solid #eee; 506 | } 507 | 508 | .iconLine { 509 | margin-top: 20rpx; 510 | } 511 | 512 | .iconLine text { 513 | font-size: 24rpx; 514 | text-align: center; 515 | color: #959595; 516 | } 517 | 518 | .iconLine view { 519 | text-align: center; 520 | } 521 | 522 | .text-center { 523 | text-align: center; 524 | } 525 | 526 | .img-menu { 527 | width: 50rpx; 528 | height: 50rpx; 529 | display: inline-block; 530 | text-align: center; 531 | } 532 | 533 | .img-menu2 { 534 | width: 60rpx; 535 | height: 60rpx; 536 | display: inline-block; 537 | text-align: center; 538 | } 539 | 540 | .emoji-move-in { 541 | -webkit-animation: emoji-move-in 0.3s forwards; 542 | animation: emoji-move-in 0.3s forwards; 543 | } 544 | 545 | .emoji-move-out { 546 | -webkit-animation: emoji-move-out 0.3s forwards; 547 | animation: emoji-move-out 0.3s forwards; 548 | } 549 | 550 | .no-emoji-move { 551 | -webkit-animation: none; 552 | animation: none; 553 | } 554 | 555 | @-webkit-keyframes emoji-move-in { 556 | 0% { 557 | margin-bottom: -90px; 558 | } 559 | 560 | 100% { 561 | margin-bottom: 0; 562 | } 563 | } 564 | 565 | @keyframes emoji-move-in { 566 | 0% { 567 | margin-bottom: -90px; 568 | } 569 | 570 | 100% { 571 | margin-bottom: 0; 572 | } 573 | } 574 | 575 | @-webkit-keyframes emoji-move-out { 576 | 0% { 577 | margin-bottom: 0; 578 | } 579 | 580 | 100% { 581 | margin-bottom: -90px; 582 | } 583 | } 584 | 585 | @keyframes emoji-move-out { 586 | 0% { 587 | margin-bottom: 0; 588 | } 589 | 590 | 100% { 591 | margin-bottom: -90px; 592 | } 593 | } 594 | 595 | /* end menu-box */ 596 | 597 | .pagination { 598 | font-weight: normal; 599 | font-size: 28rpx; 600 | line-height: 60rpx; 601 | color: #4c4c4c !important; 602 | border-bottom: 1px solid #eee; 603 | } 604 | 605 | .nav-previous { 606 | float: left; 607 | width: 80%; 608 | } 609 | 610 | .nav-next { 611 | float: right; 612 | text-align: right; 613 | width: 80%; 614 | } 615 | 616 | .canvas-box { 617 | position: fixed; 618 | top: 999999rpx; 619 | left: 0; 620 | } 621 | 622 | /* 进度条 */ 623 | 624 | .sk-three-bounce { 625 | margin: 20rpx auto; 626 | width: 200rpx; 627 | text-align: center; 628 | } 629 | 630 | .sk-three-bounce .sk-child { 631 | width: 30rpx; 632 | height: 30rpx; 633 | background-color: #118fff; 634 | border-radius: 100%; 635 | display: inline-block; 636 | -webkit-animation: sk-three-bounce 1.4s ease-in-out 0s infinite both; 637 | animation: sk-three-bounce 1.4s ease-in-out 0s infinite both; 638 | } 639 | 640 | .sk-three-bounce .sk-bounce1 { 641 | -webkit-animation-delay: -0.32s; 642 | animation-delay: -0.32s; 643 | } 644 | 645 | .sk-three-bounce .sk-bounce2 { 646 | -webkit-animation-delay: -0.16s; 647 | animation-delay: -0.16s; 648 | } 649 | 650 | @-webkit-keyframes sk-three-bounce { 651 | 0%, 80%, 100% { 652 | -webkit-transform: scale(0); 653 | transform: scale(0); 654 | } 655 | 656 | 40% { 657 | -webkit-transform: scale(1); 658 | transform: scale(1); 659 | } 660 | } 661 | 662 | @keyframes sk-three-bounce { 663 | 0%, 80%, 100% { 664 | -webkit-transform: scale(0); 665 | transform: scale(0); 666 | } 667 | 668 | 40% { 669 | -webkit-transform: scale(1); 670 | transform: scale(1); 671 | } 672 | } 673 | 674 | /* more */ 675 | 676 | .loadingmore { 677 | margin-top: 24rpx; 678 | text-align: center; 679 | margin-bottom: 24rpx; 680 | } 681 | 682 | .more-button { 683 | font-size: 0.785714286rem; 684 | font-weight: normal; 685 | color: #959595; 686 | background-color: #eee; 687 | background-repeat: repeat-x; 688 | margin-top: 30rpx; 689 | width: 240rpx; 690 | border-radius: 300rpx; 691 | } 692 | 693 | .more-button::after { 694 | border: none; 695 | } 696 | 697 | .no-more { 698 | color: #757575; 699 | font-size: 30rpx; 700 | line-height: 1.8rem; 701 | margin-bottom: 15rpx; 702 | text-align: center; 703 | margin-top: 15rpx; 704 | } 705 | 706 | /* more end */ 707 | 708 | /*common list for index list page */ 709 | 710 | .common-list { 711 | margin-bottom: 24rpx; 712 | } 713 | 714 | .common-list .list-item { 715 | position: relative; 716 | border-bottom: 1px solid #eee; 717 | padding: 24rpx; 718 | min-height: 150rpx; 719 | overflow: hidden; 720 | } 721 | 722 | .common-list .list-item.has-img image.cover { 723 | position: absolute; 724 | left: 0rpx; 725 | top: 24rpx; 726 | width: 200rpx; 727 | height: 150rpx; 728 | border-radius: 8rpx; 729 | } 730 | 731 | .common-list .list-item.has-img .content-title { 732 | margin-left: 200rpx; 733 | height: 80rpx; 734 | margin-bottom: 20rpx; 735 | } 736 | 737 | .common-list .list-item.has-img .content-title text { 738 | text-overflow: -o-ellipsis-lastline; 739 | overflow: hidden; 740 | text-overflow: ellipsis; 741 | display: -webkit-box; 742 | -webkit-line-clamp: 2; 743 | -webkit-box-orient: vertical; 744 | font-size: 30rpx; 745 | line-height: 1.4; 746 | font-weight: 400; 747 | color: #3a4040; 748 | } 749 | 750 | .common-list .list-item.has-img .content-date { 751 | margin-left: 200rpx; 752 | } 753 | 754 | .common-list .list-item.has-img .content-date image { 755 | width: 24rpx; 756 | height: 24rpx; 757 | margin-right: 10rpx; 758 | vertical-align: middle; 759 | } 760 | 761 | .common-list .list-item .content-date text { 762 | color: #959595; 763 | margin-right: 32rpx; 764 | font-size: 20rpx; 765 | line-height: 1.2; 766 | font-weight: normal; 767 | } 768 | 769 | /*common list end */ 770 | 771 | .showerror { 772 | text-align: center; 773 | font-weight: normal; 774 | font-size: 30rpx; 775 | line-height: 40rpx; 776 | color: #757575; 777 | margin-top: 100rpx; 778 | } 779 | 780 | .errortext { 781 | margin-top: 50rpx; 782 | table-layout: center; 783 | } 784 | 785 | .copyright { 786 | font-size: 26rpx; 787 | line-height: 1.6; 788 | font-weight: 400; 789 | text-align: center; 790 | color: #c4c4c4; 791 | margin-top: 48rpx; 792 | padding-bottom: 80rpx; 793 | } 794 | 795 | .common-gap { 796 | width: 100%; 797 | height: 24rpx; 798 | background-color: #f5f7f7; 799 | } 800 | -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/about.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/about_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/about_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/copy_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/copy_link.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/copy_link_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/copy_link_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/home.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/home_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/home_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/like.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/like_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/like_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/more.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/more_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/more_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/poster.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/poster_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/poster_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/reward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/reward.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/reward_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/reward_active.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/share.png -------------------------------------------------------------------------------- /miniprogram/component/NewWxComment/images/share_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/NewWxComment/images/share_active.png -------------------------------------------------------------------------------- /miniprogram/component/WxLogin/WxLogin.js: -------------------------------------------------------------------------------- 1 | // component/WxLogin/WxLogin.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | showModal: { 8 | type: Boolean, 9 | value: false, 10 | observer(newval, oldval) { 11 | var that = this; 12 | console.log(newval) 13 | console.log(oldval) 14 | that.setData({ 15 | showModal: newval 16 | }) 17 | } 18 | } 19 | }, 20 | 21 | /** 22 | * 组件的初始数据 23 | */ 24 | data: { 25 | showModal: false, 26 | }, 27 | 28 | /** 29 | * 组件的方法列表 30 | */ 31 | methods: { 32 | onGetUserInfo: function(e) { 33 | var that = this; 34 | if (e.detail.userInfo) { 35 | // 点击了确认按钮 36 | that.hideModal(); 37 | } 38 | }, 39 | hideModal: function () { 40 | var that = this; 41 | that.setData({ 42 | showModal: false 43 | }); 44 | }, 45 | } 46 | }) 47 | -------------------------------------------------------------------------------- /miniprogram/component/WxLogin/WxLogin.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /miniprogram/component/WxLogin/WxLogin.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /miniprogram/component/WxLogin/WxLogin.wxss: -------------------------------------------------------------------------------- 1 | /* component/WxLogin/WxLogin.wxss */ 2 | .modal-mask { 3 | width: 100%; 4 | height: 100%; 5 | position: fixed; 6 | top: 0; 7 | left: 0; 8 | background: #484848; 9 | opacity: 0.5; 10 | overflow: hidden; 11 | z-index: 9000; 12 | color: rgba(248, 246, 246, 0.76); 13 | align-items:center; 14 | } 15 | 16 | .modal-content { 17 | position: fixed; 18 | top: 45%; 19 | left: 0; 20 | z-index: 9500; 21 | width: 60%; 22 | height: 10%; 23 | overflow: hidden; 24 | background:white; 25 | /*top/bottom , left/right*/ 26 | margin: 0rpx 20%; 27 | border-radius: 16rpx; 28 | align-items:center; 29 | } 30 | 31 | .cell-content { 32 | display: flex; 33 | flex-direction: row; 34 | justify-content: space-between; 35 | align-items: center; 36 | width: 100%; 37 | height: 100%; 38 | } 39 | 40 | .avatar { 41 | margin: 0rpx, 0rpx; 42 | width: 40%; 43 | height: 100%; 44 | } 45 | 46 | .auth-button { 47 | line-height: 120rpx; 48 | margin: 0rpx, 0rpx; 49 | width: 60%; 50 | height: 100%; 51 | text-align: center; 52 | } -------------------------------------------------------------------------------- /miniprogram/component/WxLogin/images/login_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/miniprogram/component/WxLogin/images/login_active.png -------------------------------------------------------------------------------- /miniprogram/libs/leancloud/rest_api_leancloud.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ref : https://leancloud.cn/docs/rest_api.html 3 | */ 4 | const LeanCloud_URL_PREFIX = 'https://api.leancloud.cn/1.1/'; 5 | exports.LeanCloud_APP_ID = 'HRYpYqLTygyfRlsN8I3KEhkw-gzGzoHsz'; 6 | exports.LeanCloud_APP_KEY = '5two7AvBo3gjnH3hpYSyBW35'; 7 | 8 | //--------------------------------- 9 | // Request 10 | //--------------------------------- 11 | module.exports.showFail = function(content) { 12 | wx.showToast({ 13 | title: content + '//(ㄒoㄒ)/', 14 | icon: 'none', 15 | duration: 3000 16 | }) 17 | } 18 | 19 | var request = exports.request = function (options) { 20 | wx.showLoading({ 21 | title: '加载中', 22 | }); 23 | wx.request({ 24 | url: LeanCloud_URL_PREFIX + options.url, 25 | data: options.data, 26 | header: { 27 | 'X-LC-Id': exports.LeanCloud_APP_ID, 28 | 'X-LC-Key': exports.LeanCloud_APP_KEY, 29 | 'content-type': 'application/json; charset=utf-8' 30 | }, 31 | method: options.method || 'GET', 32 | success: function (res) { 33 | options.success && options.success(res.data); 34 | wx.hideLoading(); 35 | }, 36 | fail: function (error) { 37 | console.log(error); 38 | this.showFail('调用失败'); 39 | wx.hideLoading(); 40 | options.fail && options.fail(error); 41 | }, 42 | complete: function () { 43 | wx.hideLoading(); 44 | } 45 | }); 46 | }; -------------------------------------------------------------------------------- /miniprogram/libs/scripts/common.js: -------------------------------------------------------------------------------- 1 | const timeAgoWithTimeStr = (dateString) => { 2 | // ios: 2018/06/02 11:11:11 3 | // android: 2018-06-02 11:11:11 & 2018/06/02 11:11:11 4 | var date_time_arr = dateString.split(' '); 5 | var ios_date_arr = date_time_arr[0].split('-'); 6 | var ios_date_str = ios_date_arr[0] + '/' + ios_date_arr[1] + '/' + ios_date_arr[2]; 7 | var ios_datetime_str = ios_date_str + ' ' + date_time_arr[1]; 8 | 9 | var newDateString = dateString; 10 | newDateString = ios_datetime_str; 11 | 12 | var date = new Date(newDateString) 13 | 14 | try { 15 | var oldTime = date.getTime(); 16 | var currTime = new Date().getTime(); 17 | var diffValue = currTime - oldTime; 18 | 19 | var days = Math.floor(diffValue / (24 * 3600 * 1000)); 20 | 21 | if (days === 0) { 22 | // 计算相差小时数 23 | var leave1 = diffValue % (24 * 3600 * 1000); // 计算天数后剩余的毫秒数 24 | var hours = Math.floor(leave1 / (3600 * 1000)); 25 | if (hours === 0) { 26 | // 计算相差分钟数 27 | var leave2 = leave1 % (3600 * 1000); // 计算小时数后剩余的毫秒数 28 | var minutes = Math.floor(leave2 / (60 * 1000)); 29 | if (minutes === 0) { 30 | // 计算相差秒数 31 | var leave3 = leave2 % (60 * 1000); // 计算分钟数后剩余的毫秒数 32 | var seconds = Math.round(leave3 / 1000); 33 | return seconds + ' 秒前'; 34 | } 35 | return minutes + ' 分钟前'; 36 | } 37 | return hours + ' 小时前'; 38 | } 39 | if (days < 0) return '刚刚'; 40 | 41 | if (days < 3) { 42 | return days + ' 天前'; 43 | } else { 44 | return dateString 45 | } 46 | } catch (error) { 47 | console.log(error) 48 | } 49 | } 50 | 51 | function getTime() { 52 | // 获取当前时间戳 53 | var timestamp = Date.parse(new Date()); 54 | var n = timestamp; 55 | var date = new Date(n); 56 | // 年 57 | var Y = date.getFullYear(); 58 | // 月 59 | var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1); 60 | // 日 61 | var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); 62 | // 时 63 | var h = date.getHours(); 64 | // 分 65 | var m = date.getMinutes(); 66 | // 秒 67 | var s = date.getSeconds(); 68 | return Y + '-' + M + '-' + D + ' ' + h + ":" + m + ":" + s; 69 | } 70 | 71 | module.exports = { 72 | timeAgoWithTimeStr: timeAgoWithTimeStr, 73 | getTime: getTime 74 | } 75 | -------------------------------------------------------------------------------- /miniprogram/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | motto: 'Hello World', 8 | userInfo: {}, 9 | hasUserInfo: false, 10 | canIUse: wx.canIUse('button.open-type.getUserInfo') 11 | }, 12 | //事件处理函数 13 | bindViewTap: function() { 14 | wx.navigateTo({ 15 | url: '../logs/logs' 16 | }) 17 | }, 18 | onLoad: function() { 19 | if (app.globalData.userInfo) { 20 | this.setData({ 21 | userInfo: app.globalData.userInfo, 22 | hasUserInfo: true 23 | }) 24 | } else if (this.data.canIUse) { 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | app.userInfoReadyCallback = res => { 28 | this.setData({ 29 | userInfo: res.userInfo, 30 | hasUserInfo: true 31 | }) 32 | } 33 | } else { 34 | // 在没有 open-type=getUserInfo 版本的兼容处理 35 | wx.getUserInfo({ 36 | success: res => { 37 | app.globalData.userInfo = res.userInfo 38 | this.setData({ 39 | userInfo: res.userInfo, 40 | hasUserInfo: true 41 | }) 42 | } 43 | }) 44 | } 45 | }, 46 | getUserInfo: function(e) { 47 | console.log(e) 48 | app.globalData.userInfo = e.detail.userInfo 49 | this.setData({ 50 | userInfo: e.detail.userInfo, 51 | hasUserInfo: true 52 | }) 53 | }, 54 | onReachBottom: function() { 55 | let newWxComment = this.selectComponent('#NewWxComment'); 56 | newWxComment.onReachBottom(); 57 | } 58 | }) -------------------------------------------------------------------------------- /miniprogram/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "主页", 3 | "enablePullDownRefresh": false, 4 | "usingComponents": { 5 | "NewWxComment": "/component/NewWxComment/NewWxComment" 6 | } 7 | } -------------------------------------------------------------------------------- /miniprogram/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 本教程全面介绍 JavaScript 核心语法,从最简单的讲起,循序渐进、由浅入深,力求清晰易懂。所有章节都带有大量的代码实例,便于理解和模仿,可以用到实际项目中,即学即用。 5 | 6 | 本教程适合初学者当作 JavaScript 语言入门教程,也适合当作日常使用的参考手册。 7 | 8 | 什么是 JavaScript 语言? 9 | JavaScript 是一种轻量级的脚本语言。所谓“脚本语言”(script language),指的是它不具备开发操作系统的能力,而是只用来编写控制其他大型应用程序(比如浏览器)的“脚本”。 10 | 11 | JavaScript 也是一种嵌入式(embedded)语言。它本身提供的核心语法不算很多,只能用来做一些数学和逻辑运算。JavaScript 本身不提供任何与 I/O(输入/输出)相关的 API,都要靠宿主环境(host)提供,所以 JavaScript 只合适嵌入更大型的应用程序环境,去调用宿主环境提供的底层 API。 12 | 13 | 目前,已经嵌入 JavaScript 的宿主环境有多种,最常见的环境就是浏览器,另外还有服务器环境,也就是 Node 项目。 14 | 15 | 从语法角度看,JavaScript 语言是一种“对象模型”语言。各种宿主环境通过这个模型,描述自己的功能和操作接口,从而通过 JavaScript 控制这些功能。但是,JavaScript 并不是纯粹的“面向对象语言”,还支持其他编程范式(比如函数式编程)。这导致几乎任何一个问题,JavaScript 都有多种解决方法。阅读本书的过程中,你会诧异于 JavaScript 语法的灵活性。 16 | 17 | JavaScript 的核心语法部分相当精简,只包括两个部分:基本的语法构造(比如操作符、控制结构、语句)和标准库(就是一系列具有各种功能的对象比如Array、Date、Math等)。除此之外,各种宿主环境提供额外的 API(即只能在该环境使用的接口),以便 JavaScript 调用。以浏览器为例,它提供的额外 API 可以分成三大类。 18 | 19 | 20 | -------------------------------------------------------------------------------- /miniprogram/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .userinfo { 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | 8 | .userinfo-avatar { 9 | width: 128rpx; 10 | height: 128rpx; 11 | margin: 20rpx; 12 | border-radius: 50%; 13 | } 14 | 15 | .userinfo-nickname { 16 | color: #aaa; 17 | } 18 | 19 | .usermotto { 20 | margin-top: 200px; 21 | } -------------------------------------------------------------------------------- /miniprogram/pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | //logs.js 2 | const util = require('../../utils/util.js') 3 | 4 | Page({ 5 | data: { 6 | logs: [] 7 | }, 8 | onLoad: function () { 9 | this.setData({ 10 | logs: (wx.getStorageSync('logs') || []).map(log => { 11 | return util.formatTime(new Date(log)) 12 | }) 13 | }) 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /miniprogram/pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "查看启动日志", 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /miniprogram/pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{index + 1}}. {{log}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /miniprogram/pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | .log-list { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 40rpx; 5 | } 6 | .log-item { 7 | margin: 10rpx; 8 | } 9 | -------------------------------------------------------------------------------- /miniprogram/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /miniprogram/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "miniprogramRoot": "miniprogram/", 4 | "packOptions": { 5 | "ignore": [] 6 | }, 7 | "setting": { 8 | "urlCheck": false, 9 | "es6": false, 10 | "enhance": false, 11 | "postcss": true, 12 | "minified": true, 13 | "newFeature": true, 14 | "coverView": true, 15 | "autoAudits": false, 16 | "checkInvalidKey": true, 17 | "checkSiteMap": true, 18 | "uploadWithSourceMap": true, 19 | "babelSetting": { 20 | "ignore": [], 21 | "disablePlugins": [], 22 | "outputPath": "" 23 | } 24 | }, 25 | "compileType": "miniprogram", 26 | "libVersion": "2.8.2", 27 | "appid": "wx40b8ecd087d22fd1", 28 | "projectname": "NewWxComment", 29 | "debugOptions": { 30 | "hidedInDevtools": [] 31 | }, 32 | "isGameTourist": false, 33 | "simulatorType": "wechat", 34 | "simulatorPluginLibVersion": {}, 35 | "condition": { 36 | "search": { 37 | "current": -1, 38 | "list": [] 39 | }, 40 | "conversation": { 41 | "current": -1, 42 | "list": [] 43 | }, 44 | "game": { 45 | "currentL": -1, 46 | "list": [] 47 | }, 48 | "miniprogram": { 49 | "current": -1, 50 | "list": [] 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /screenshots/NewWxComment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/screenshots/NewWxComment.png -------------------------------------------------------------------------------- /screenshots/Xiaobaiai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicm/NewWxComment/7b0f3e35aa8f689adef3e6de7f45c343fcf3d307/screenshots/Xiaobaiai.jpg --------------------------------------------------------------------------------