新闻初版
This commit is contained in:
commit
1b52c78fe7
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Mac
|
||||||
|
.DS_Store
|
||||||
|
**/.DS_Store
|
||||||
|
|
||||||
|
# vim/vi
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# JavaScript
|
||||||
|
node_modules/
|
||||||
|
.node_modules/
|
||||||
|
.eslintcache
|
||||||
|
unpackage/dist/build/
|
||||||
|
unpackage/dist/dev/
|
||||||
|
|
||||||
|
# python
|
||||||
|
*.pyc
|
||||||
|
/.hbuilderx/
|
||||||
|
/unpackage/
|
53
App.vue
Normal file
53
App.vue
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
onLaunch: function() {
|
||||||
|
console.log('App Launch');
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
plus.screen.lockOrientation('portrait-primary');
|
||||||
|
|
||||||
|
let appid = plus.runtime.appid;
|
||||||
|
if (appid && appid.toLocaleLowerCase() != "hbuilder") {
|
||||||
|
uni.request({
|
||||||
|
url: 'https://uniapp.dcloud.io/update', //检查更新的服务器地址
|
||||||
|
data: {
|
||||||
|
appid: plus.runtime.appid,
|
||||||
|
version: plus.runtime.version
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
console.log('success', res);
|
||||||
|
if (res.statusCode == 200 && res.data.isUpdate) {
|
||||||
|
let openUrl = plus.os.name === 'iOS' ? res.data.iOS : res.data.Android;
|
||||||
|
// 提醒用户更新
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新提示',
|
||||||
|
content: res.data.note ? res.data.note : '是否选择更新',
|
||||||
|
success: (showResult) => {
|
||||||
|
if (showResult.confirm) {
|
||||||
|
plus.runtime.openURL(openUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var domModule = weex.requireModule('dom');
|
||||||
|
domModule.addRule('fontFace', {
|
||||||
|
'fontFamily': "texticons",
|
||||||
|
'src': "url('./static/text-icon.ttf')"
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
onShow: function() {
|
||||||
|
console.log('App Show')
|
||||||
|
},
|
||||||
|
onHide: function() {
|
||||||
|
console.log('App Hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/*每个页面公共css */
|
||||||
|
</style>
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 DCloud
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
22
README.md
Normal file
22
README.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# uni-template-news
|
||||||
|
基于uni-app开发的新闻/资讯类App模板
|
||||||
|
|
||||||
|
## 体验方式
|
||||||
|
同步/下载项目后,拖入 HBuilderX 中即可运行体验。
|
||||||
|
|
||||||
|
## 特点
|
||||||
|
* 兼容多个平台
|
||||||
|
* 自定义组件实现顶部选项卡切换
|
||||||
|
* App 平台使用 nvue 进一步优化体验
|
||||||
|
|
||||||
|
### 平台支持
|
||||||
|
* app-vue
|
||||||
|
* app-nvue
|
||||||
|
* H5
|
||||||
|
* 微信小程序
|
||||||
|
* 支付宝小程序
|
||||||
|
* 百度小程序
|
||||||
|
* 头条小程序
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
* 非 App-nvue 平台暂不支持下拉刷新
|
23
changelog.md
Normal file
23
changelog.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
## 3.1.7(2022-06-30)
|
||||||
|
- 新增 支持 ios 安全区
|
||||||
|
## 3.1.6(2022-02-08)
|
||||||
|
- 移除无效的H5平台百度统计
|
||||||
|
## 3.1.5(2021-11-26)
|
||||||
|
- 新增 小程序平台支持VUE3 (HBuilderX 3.3+)
|
||||||
|
- 修复 某些情况下无法滚动的问题
|
||||||
|
## 3.1.4(2021-07-30)
|
||||||
|
- 适配 VUE3 (需要 HBuilderX 3.2.0+)
|
||||||
|
## 3.1.3(2021-07-28)
|
||||||
|
- 适配 VUE3 (需要 HBuilderX 3.2.0+)
|
||||||
|
## 3.0.0(2021-02-19)
|
||||||
|
- 修复 某些操作导致上拉加载无效的问题
|
||||||
|
## 2.9.5(2020-10-23)
|
||||||
|
- 修复 app 平台 ios 顶部页签高度显示不正确的问题
|
||||||
|
## 2.9.2(2020-09-27)
|
||||||
|
- 修复app平台运行时出错的bug
|
||||||
|
## 2.9.1(2020-09-27)
|
||||||
|
- 修复加载更多文字过大问题
|
||||||
|
## 2.9.0(2020-09-25)
|
||||||
|
- 适配大屏
|
||||||
|
## 2.4.2(2019-11-18)
|
||||||
|
- 重构代码,支持编译到所有平台
|
352
common/html-parser.js
Normal file
352
common/html-parser.js
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* HTML5 Parser By Sam Blowes
|
||||||
|
*
|
||||||
|
* Designed for HTML5 documents
|
||||||
|
*
|
||||||
|
* Original code by John Resig (ejohn.org)
|
||||||
|
* http://ejohn.org/blog/pure-javascript-html-parser/
|
||||||
|
* Original code by Erik Arvidsson, Mozilla Public License
|
||||||
|
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* License
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This code is triple licensed using Apache Software License 2.0,
|
||||||
|
* Mozilla Public License or GNU Public License
|
||||||
|
*
|
||||||
|
* ////////////////////////////////////////////////////////////////////////////
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy
|
||||||
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* ////////////////////////////////////////////////////////////////////////////
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License
|
||||||
|
* Version 1.1 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS"
|
||||||
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing rights and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is Simple HTML Parser.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Erik Arvidsson.
|
||||||
|
* Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights
|
||||||
|
* Reserved.
|
||||||
|
*
|
||||||
|
* ////////////////////////////////////////////////////////////////////////////
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* Usage
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* // Use like so:
|
||||||
|
* HTMLParser(htmlString, {
|
||||||
|
* start: function(tag, attrs, unary) {},
|
||||||
|
* end: function(tag) {},
|
||||||
|
* chars: function(text) {},
|
||||||
|
* comment: function(text) {}
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // or to get an XML string:
|
||||||
|
* HTMLtoXML(htmlString);
|
||||||
|
*
|
||||||
|
* // or to get an XML DOM Document
|
||||||
|
* HTMLtoDOM(htmlString);
|
||||||
|
*
|
||||||
|
* // or to inject into an existing document/DOM node
|
||||||
|
* HTMLtoDOM(htmlString, document);
|
||||||
|
* HTMLtoDOM(htmlString, document.body);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// Regular Expressions for parsing tags and attributes
|
||||||
|
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
|
||||||
|
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
|
||||||
|
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
|
||||||
|
|
||||||
|
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
|
||||||
|
// fixed by xxx 将 ins 标签从块级名单中移除
|
||||||
|
|
||||||
|
var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5
|
||||||
|
|
||||||
|
var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open
|
||||||
|
// (and which close themselves)
|
||||||
|
|
||||||
|
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
|
||||||
|
|
||||||
|
var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
|
||||||
|
|
||||||
|
var special = makeMap('script,style');
|
||||||
|
function HTMLParser(html, handler) {
|
||||||
|
var index;
|
||||||
|
var chars;
|
||||||
|
var match;
|
||||||
|
var stack = [];
|
||||||
|
var last = html;
|
||||||
|
|
||||||
|
stack.last = function () {
|
||||||
|
return this[this.length - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
while (html) {
|
||||||
|
chars = true; // Make sure we're not in a script or style element
|
||||||
|
|
||||||
|
if (!stack.last() || !special[stack.last()]) {
|
||||||
|
// Comment
|
||||||
|
if (html.indexOf('<!--') == 0) {
|
||||||
|
index = html.indexOf('-->');
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
if (handler.comment) {
|
||||||
|
handler.comment(html.substring(4, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
html = html.substring(index + 3);
|
||||||
|
chars = false;
|
||||||
|
} // end tag
|
||||||
|
|
||||||
|
} else if (html.indexOf('</') == 0) {
|
||||||
|
match = html.match(endTag);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
html = html.substring(match[0].length);
|
||||||
|
match[0].replace(endTag, parseEndTag);
|
||||||
|
chars = false;
|
||||||
|
} // start tag
|
||||||
|
|
||||||
|
} else if (html.indexOf('<') == 0) {
|
||||||
|
match = html.match(startTag);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
html = html.substring(match[0].length);
|
||||||
|
match[0].replace(startTag, parseStartTag);
|
||||||
|
chars = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chars) {
|
||||||
|
index = html.indexOf('<');
|
||||||
|
var text = index < 0 ? html : html.substring(0, index);
|
||||||
|
html = index < 0 ? '' : html.substring(index);
|
||||||
|
|
||||||
|
if (handler.chars) {
|
||||||
|
handler.chars(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) {
|
||||||
|
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2');
|
||||||
|
|
||||||
|
if (handler.chars) {
|
||||||
|
handler.chars(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
parseEndTag('', stack.last());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (html == last) {
|
||||||
|
throw 'Parse Error: ' + html;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = html;
|
||||||
|
} // Clean up any remaining tags
|
||||||
|
|
||||||
|
|
||||||
|
parseEndTag();
|
||||||
|
|
||||||
|
function parseStartTag(tag, tagName, rest, unary) {
|
||||||
|
tagName = tagName.toLowerCase();
|
||||||
|
|
||||||
|
if (block[tagName]) {
|
||||||
|
while (stack.last() && inline[stack.last()]) {
|
||||||
|
parseEndTag('', stack.last());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closeSelf[tagName] && stack.last() == tagName) {
|
||||||
|
parseEndTag('', tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
unary = empty[tagName] || !!unary;
|
||||||
|
|
||||||
|
if (!unary) {
|
||||||
|
stack.push(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler.start) {
|
||||||
|
var attrs = [];
|
||||||
|
rest.replace(attr, function (match, name) {
|
||||||
|
var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : '';
|
||||||
|
attrs.push({
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (handler.start) {
|
||||||
|
handler.start(tagName, attrs, unary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseEndTag(tag, tagName) {
|
||||||
|
// If no tag name is provided, clean shop
|
||||||
|
if (!tagName) {
|
||||||
|
var pos = 0;
|
||||||
|
} // Find the closest opened tag of the same type
|
||||||
|
else {
|
||||||
|
for (var pos = stack.length - 1; pos >= 0; pos--) {
|
||||||
|
if (stack[pos] == tagName) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= 0) {
|
||||||
|
// Close all the open elements, up the stack
|
||||||
|
for (var i = stack.length - 1; i >= pos; i--) {
|
||||||
|
if (handler.end) {
|
||||||
|
handler.end(stack[i]);
|
||||||
|
}
|
||||||
|
} // Remove the open elements from the stack
|
||||||
|
|
||||||
|
|
||||||
|
stack.length = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeMap(str) {
|
||||||
|
var obj = {};
|
||||||
|
var items = str.split(',');
|
||||||
|
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
obj[items[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDOCTYPE(html) {
|
||||||
|
return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAttrs(attrs) {
|
||||||
|
return attrs.reduce(function (pre, attr) {
|
||||||
|
var value = attr.value;
|
||||||
|
var name = attr.name;
|
||||||
|
|
||||||
|
if (pre[name]) {
|
||||||
|
pre[name] = pre[name] + " " + value;
|
||||||
|
} else {
|
||||||
|
pre[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pre;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHtml(html) {
|
||||||
|
html = removeDOCTYPE(html);
|
||||||
|
var stacks = [];
|
||||||
|
var results = {
|
||||||
|
node: 'root',
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
HTMLParser(html, {
|
||||||
|
start: function start(tag, attrs, unary) {
|
||||||
|
var node = {
|
||||||
|
name: tag
|
||||||
|
};
|
||||||
|
|
||||||
|
if (attrs.length !== 0) {
|
||||||
|
node.attrs = parseAttrs(attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unary) {
|
||||||
|
var parent = stacks[0] || results;
|
||||||
|
|
||||||
|
if (!parent.children) {
|
||||||
|
parent.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.push(node);
|
||||||
|
} else {
|
||||||
|
stacks.unshift(node);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
end: function end(tag) {
|
||||||
|
var node = stacks.shift();
|
||||||
|
if (node.name !== tag) console.error('invalid state: mismatch end tag');
|
||||||
|
|
||||||
|
if (stacks.length === 0) {
|
||||||
|
results.children.push(node);
|
||||||
|
} else {
|
||||||
|
var parent = stacks[0];
|
||||||
|
|
||||||
|
if (!parent.children) {
|
||||||
|
parent.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.push(node);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chars: function chars(text) {
|
||||||
|
var node = {
|
||||||
|
type: 'text',
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
|
||||||
|
if (stacks.length === 0) {
|
||||||
|
results.children.push(node);
|
||||||
|
} else {
|
||||||
|
var parent = stacks[0];
|
||||||
|
|
||||||
|
if (!parent.children) {
|
||||||
|
parent.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.push(node);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
comment: function comment(text) {
|
||||||
|
var node = {
|
||||||
|
node: 'comment',
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
var parent = stacks[0];
|
||||||
|
|
||||||
|
if (!parent.children) {
|
||||||
|
parent.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default parseHtml;
|
52
common/util.js
Normal file
52
common/util.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
function friendlyDate(timestamp) {
|
||||||
|
var formats = {
|
||||||
|
'year': '%n% 年前',
|
||||||
|
'month': '%n% 月前',
|
||||||
|
'day': '%n% 天前',
|
||||||
|
'hour': '%n% 小时前',
|
||||||
|
'minute': '%n% 分钟前',
|
||||||
|
'second': '%n% 秒前',
|
||||||
|
};
|
||||||
|
|
||||||
|
var now = Date.now();
|
||||||
|
var seconds = Math.floor((now - timestamp) / 1000);
|
||||||
|
var minutes = Math.floor(seconds / 60);
|
||||||
|
var hours = Math.floor(minutes / 60);
|
||||||
|
var days = Math.floor(hours / 24);
|
||||||
|
var months = Math.floor(days / 30);
|
||||||
|
var years = Math.floor(months / 12);
|
||||||
|
|
||||||
|
var diffType = '';
|
||||||
|
var diffValue = 0;
|
||||||
|
if (years > 0) {
|
||||||
|
diffType = 'year';
|
||||||
|
diffValue = years;
|
||||||
|
} else {
|
||||||
|
if (months > 0) {
|
||||||
|
diffType = 'month';
|
||||||
|
diffValue = months;
|
||||||
|
} else {
|
||||||
|
if (days > 0) {
|
||||||
|
diffType = 'day';
|
||||||
|
diffValue = days;
|
||||||
|
} else {
|
||||||
|
if (hours > 0) {
|
||||||
|
diffType = 'hour';
|
||||||
|
diffValue = hours;
|
||||||
|
} else {
|
||||||
|
if (minutes > 0) {
|
||||||
|
diffType = 'minute';
|
||||||
|
diffValue = minutes;
|
||||||
|
} else {
|
||||||
|
diffType = 'second';
|
||||||
|
diffValue = seconds === 0 ? (seconds = 1) : seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formats[diffType].replace('%n%', diffValue);
|
||||||
|
}
|
||||||
|
export {
|
||||||
|
friendlyDate
|
||||||
|
}
|
188
components/nodata.nvue
Normal file
188
components/nodata.nvue
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<view class="nodata">
|
||||||
|
<view class="nodata-content">
|
||||||
|
<view class="text-view a-i-c j-c-c t-a-c">
|
||||||
|
<text class="title">{{textTypes[networkType]}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="icon-view"></view>
|
||||||
|
<view class="opera-view">
|
||||||
|
<view class="btn btn-default" v-if="networkType!='none'" @click="retry">
|
||||||
|
<text class="btn-text">重试</text>
|
||||||
|
</view>
|
||||||
|
<view class="btn btn-default" v-if="networkType=='none'" @click="openSettings">
|
||||||
|
<text class="btn-text">设置</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'nodata',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
textTypes: {
|
||||||
|
none: "暂无网络"
|
||||||
|
},
|
||||||
|
isConnected: false,
|
||||||
|
networkType: "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.isIOS = (uni.getSystemInfoSync().platform === 'ios');
|
||||||
|
uni.onNetworkStatusChange((res) => {
|
||||||
|
this.isConnected = res.isConnected;
|
||||||
|
this.networkType = res.networkType;
|
||||||
|
});
|
||||||
|
uni.getNetworkType({
|
||||||
|
success: (res) => {
|
||||||
|
this.networkType = res.networkType;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
retry() {
|
||||||
|
this.$emit('retry');
|
||||||
|
},
|
||||||
|
async openSettings() {
|
||||||
|
if (this.networkType == "none") {
|
||||||
|
this.openSystemSettings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openAppSettings() {
|
||||||
|
this.gotoAppSetting();
|
||||||
|
},
|
||||||
|
openSystemSettings() {
|
||||||
|
if (this.isIOS) {
|
||||||
|
this.gotoiOSSetting();
|
||||||
|
} else {
|
||||||
|
this.gotoAndroidSetting();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
network() {
|
||||||
|
var result = null;
|
||||||
|
var cellularData = plus.ios.newObject("CTCellularData");
|
||||||
|
var state = cellularData.plusGetAttribute("restrictedState");
|
||||||
|
if (state == 0) {
|
||||||
|
result = null;
|
||||||
|
console.log("StateUnknown");
|
||||||
|
} else if (state == 2) {
|
||||||
|
result = 1;
|
||||||
|
console.log("已经开启了互联网权限:NotRestricted");
|
||||||
|
} else if (state == 1) {
|
||||||
|
result = 2;
|
||||||
|
console.log("Restricted");
|
||||||
|
}
|
||||||
|
plus.ios.deleteObject(cellularData);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
gotoAppSetting() {
|
||||||
|
if (this.isIOS) {
|
||||||
|
var UIApplication = plus.ios.import("UIApplication");
|
||||||
|
var application2 = UIApplication.sharedApplication();
|
||||||
|
var NSURL2 = plus.ios.import("NSURL");
|
||||||
|
var setting2 = NSURL2.URLWithString("app-settings:");
|
||||||
|
application2.openURL(setting2);
|
||||||
|
plus.ios.deleteObject(setting2);
|
||||||
|
plus.ios.deleteObject(NSURL2);
|
||||||
|
plus.ios.deleteObject(application2);
|
||||||
|
} else {
|
||||||
|
var Intent = plus.android.importClass("android.content.Intent");
|
||||||
|
var Settings = plus.android.importClass("android.provider.Settings");
|
||||||
|
var Uri = plus.android.importClass("android.net.Uri");
|
||||||
|
var mainActivity = plus.android.runtimeMainActivity();
|
||||||
|
var intent = new Intent();
|
||||||
|
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
|
var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
|
||||||
|
intent.setData(uri);
|
||||||
|
mainActivity.startActivity(intent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gotoiOSSetting() {
|
||||||
|
var UIApplication = plus.ios.import("UIApplication");
|
||||||
|
var application2 = UIApplication.sharedApplication();
|
||||||
|
var NSURL2 = plus.ios.import("NSURL");
|
||||||
|
var setting2 = NSURL2.URLWithString("App-prefs:root=General");
|
||||||
|
application2.openURL(setting2);
|
||||||
|
plus.ios.deleteObject(setting2);
|
||||||
|
plus.ios.deleteObject(NSURL2);
|
||||||
|
plus.ios.deleteObject(application2);
|
||||||
|
},
|
||||||
|
gotoAndroidSetting() {
|
||||||
|
var Intent = plus.android.importClass("android.content.Intent");
|
||||||
|
var Settings = plus.android.importClass("android.provider.Settings");
|
||||||
|
var mainActivity = plus.android.runtimeMainActivity();
|
||||||
|
var intent = new Intent(Settings.ACTION_SETTINGS);
|
||||||
|
mainActivity.startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.a-i-c {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-c-c {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-a-c {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodata {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodata-content {
|
||||||
|
transform: translateY(-50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-view {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opera-view {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 128px;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-text {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default {
|
||||||
|
border-color: #999999;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
130
components/uni-list.vue
Normal file
130
components/uni-list.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<!-- #ifdef APP-VUE -->
|
||||||
|
<view class="uni-list">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-NVUE -->
|
||||||
|
<list ref="list" class="uni-list" :enableBackToTop="enableBackToTop" loadmoreoffset="15" :scroll-y="scrollY" @loadmore="loadMore">
|
||||||
|
<slot />
|
||||||
|
</list>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef H5 || MP-WEIXIN || MP-QQ -->
|
||||||
|
<scroll-view class="uni-list" :enableBackToTop="enableBackToTop" :scroll-y="scrollY" @scrolltolower="loadMore">
|
||||||
|
<slot />
|
||||||
|
</scroll-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO -->
|
||||||
|
<scroll-view class="uni-list" :scroll-y="scrollY" @scrolltolower="loadMore">
|
||||||
|
<slot />
|
||||||
|
</scroll-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'UniList',
|
||||||
|
'mp-weixin': {
|
||||||
|
options: {
|
||||||
|
multipleSlots: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
enableBackToTop: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
scrollY: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
this.pullDown = {
|
||||||
|
threshold: 95,
|
||||||
|
maxHeight: 200,
|
||||||
|
callRefresh: 'onrefresh',
|
||||||
|
callPullingDown: 'onpullingdown',
|
||||||
|
refreshSelector: '.uni-refresh'
|
||||||
|
};
|
||||||
|
this.height = 0;
|
||||||
|
this.canPullDown = false;
|
||||||
|
this.refreshInstance = {};
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadMore(e) {
|
||||||
|
this.$emit("scrolltolower");
|
||||||
|
},
|
||||||
|
resetLoadmore() {
|
||||||
|
this.$refs.list.resetLoadmore();
|
||||||
|
},
|
||||||
|
ontouchstart(e) {
|
||||||
|
if (!this.canPullDown) {
|
||||||
|
console.log("canPullDown", this.canPullDown);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.height = 0;
|
||||||
|
this.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
|
||||||
|
this._updateRefresh(0);
|
||||||
|
this.refreshInstance.callMethod("onchange", true);
|
||||||
|
},
|
||||||
|
ontouchmove(e) {
|
||||||
|
if (!this.canPullDown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldHeight = this.height;
|
||||||
|
var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
|
||||||
|
var newHeight = endY - this.touchStartY;
|
||||||
|
if (newHeight > this.pullDown.maxHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateRefresh(newHeight);
|
||||||
|
|
||||||
|
newHeight = newHeight < this.pullDown.maxHeight ? newHeight : this.pullDown.maxHeight;
|
||||||
|
this.height = newHeight;
|
||||||
|
|
||||||
|
this.refreshInstance.callMethod(this.pullDown.callPullingDown, {
|
||||||
|
height: newHeight
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ontouchend(e) {
|
||||||
|
if (!this.canPullDown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshInstance.callMethod("onchange", false);
|
||||||
|
|
||||||
|
if (this.height > this.pullDown.threshold) {
|
||||||
|
refreshInstance.callMethod(this.pullDown.callRefresh);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateRefresh(0);
|
||||||
|
},
|
||||||
|
_updateRefresh(height) {
|
||||||
|
this.refreshInstance.setStyle({
|
||||||
|
'height': height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.uni-list {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
</style>
|
381
components/uni-load-more.vue
Normal file
381
components/uni-load-more.vue
Normal file
File diff suppressed because one or more lines are too long
85
components/uni-refresh.wxs
Normal file
85
components/uni-refresh.wxs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
var pullDown = {
|
||||||
|
threshold: 95,
|
||||||
|
maxHeight: 200,
|
||||||
|
callRefresh: 'onrefresh',
|
||||||
|
callPullingDown: 'onpullingdown',
|
||||||
|
refreshSelector: '.uni-refresh'
|
||||||
|
};
|
||||||
|
|
||||||
|
function ready(newValue, oldValue, ownerInstance, instance) {
|
||||||
|
var state = instance.getState()
|
||||||
|
state.canPullDown = newValue;
|
||||||
|
console.log(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchStart(e, instance) {
|
||||||
|
var state = instance.getState();
|
||||||
|
state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
|
||||||
|
state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
|
||||||
|
if (!state.canPullDown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state.height = 0;
|
||||||
|
state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
|
||||||
|
state.refreshInstance.setStyle({
|
||||||
|
'height': 0
|
||||||
|
});
|
||||||
|
state.refreshInstance.callMethod("onchange", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchMove(e, ownerInstance) {
|
||||||
|
var instance = e.instance;
|
||||||
|
var state = instance.getState();
|
||||||
|
if (!state.canPullDown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldHeight = state.height;
|
||||||
|
var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
|
||||||
|
var height = endY - state.touchStartY;
|
||||||
|
if (height > pullDown.maxHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var refreshInstance = state.refreshInstance;
|
||||||
|
refreshInstance.setStyle({
|
||||||
|
'height': height + 'px'
|
||||||
|
});
|
||||||
|
|
||||||
|
height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
|
||||||
|
state.height = height;
|
||||||
|
refreshInstance.callMethod(pullDown.callPullingDown, {
|
||||||
|
height: height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchEnd(e, ownerInstance) {
|
||||||
|
var state = e.instance.getState();
|
||||||
|
if (!state.canPullDown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state.refreshInstance.callMethod("onchange", false);
|
||||||
|
|
||||||
|
var refreshInstance = state.refreshInstance;
|
||||||
|
if (state.height > pullDown.threshold) {
|
||||||
|
refreshInstance.callMethod(pullDown.callRefresh);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshInstance.setStyle({
|
||||||
|
'height': 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function propObserver(newValue, oldValue, instance) {
|
||||||
|
pullDown = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
touchmove: touchMove,
|
||||||
|
touchstart: touchStart,
|
||||||
|
touchend: touchEnd,
|
||||||
|
propObserver: propObserver
|
||||||
|
}
|
45
h5.template.html
Normal file
45
h5.template.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title>
|
||||||
|
<%= htmlWebpackPlugin.options.title %>
|
||||||
|
</title>
|
||||||
|
<script>
|
||||||
|
var UA = window.navigator.userAgent.toLowerCase();
|
||||||
|
var isAndroid = UA.indexOf('android') > 0;
|
||||||
|
var isIOS = /iphone|ipad|ipod|ios/.test(UA);
|
||||||
|
if (!(isAndroid || isIOS)) {
|
||||||
|
// 正式发布的时候使用,开发期间不启用。
|
||||||
|
// window.location.href = '/demo/news/website/pcguide.html';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="<%= BASE_URL %>static/index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- 该文件为 H5 平台的模板 HTML,并非应用入口,请勿直接运行此文件。 -->
|
||||||
|
<!-- 详见文档:https://uniapp.dcloud.io/collocation/manifest?id=h5-template -->
|
||||||
|
<noscript>
|
||||||
|
<strong>Please enable JavaScript to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
<script>
|
||||||
|
var _hmt = _hmt || [];
|
||||||
|
(function() {
|
||||||
|
var hm = document.createElement("script");
|
||||||
|
hm.src = "https://hm.baidu.com/hm.js?fe3b7a223fc08c795f0f4b6350703e6f";
|
||||||
|
var s = document.getElementsByTagName("script")[0];
|
||||||
|
s.parentNode.insertBefore(hm, s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
20
index.html
Normal file
20
index.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"><!--app-html--></div>
|
||||||
|
<script type="module" src="/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
main.js
Normal file
26
main.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
const host = 'https://unidemo.dcloud.net.cn/';
|
||||||
|
|
||||||
|
// #ifndef VUE3
|
||||||
|
import Vue from 'vue'
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
Vue.prototype.$host = host;
|
||||||
|
App.mpType = 'app'
|
||||||
|
const app = new Vue({
|
||||||
|
...App
|
||||||
|
})
|
||||||
|
app.$mount()
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef VUE3
|
||||||
|
import {
|
||||||
|
createSSRApp
|
||||||
|
} from 'vue'
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App)
|
||||||
|
return {
|
||||||
|
app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
108
manifest.json
Normal file
108
manifest.json
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"name" : "news",
|
||||||
|
"appid" : "__UNI__8C5575B",
|
||||||
|
"description" : "基于uni-app开发的新闻/资讯类App模板",
|
||||||
|
"versionName" : "3.1.23",
|
||||||
|
"versionCode" : 1,
|
||||||
|
"transformPx" : false,
|
||||||
|
"uniStatistics" : {
|
||||||
|
"enable" : false
|
||||||
|
},
|
||||||
|
"compatConfig" : {
|
||||||
|
"MODE" : 2 // 2代表兼容Vue2模式,3代表非兼容Vue2模式
|
||||||
|
},
|
||||||
|
"app-plus" : {
|
||||||
|
"usingComponents" : true,
|
||||||
|
"nvueCompiler" : "uni-app",
|
||||||
|
/* 5+App特有相关 */
|
||||||
|
"modules" : {},
|
||||||
|
/* 模块配置 */
|
||||||
|
"distribute" : {
|
||||||
|
/* 应用发布信息 */
|
||||||
|
"android" : {
|
||||||
|
/* android打包配置 */
|
||||||
|
"permissions" : [
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||||
|
],
|
||||||
|
"permissionPhoneState" : {
|
||||||
|
"request" : "none"
|
||||||
|
},
|
||||||
|
"abiFilters" : [ "armeabi-v7a" ]
|
||||||
|
},
|
||||||
|
"ios" : {
|
||||||
|
"idfa" : false
|
||||||
|
},
|
||||||
|
/* ios打包配置 */
|
||||||
|
"sdkConfigs" : {
|
||||||
|
"ad" : {}
|
||||||
|
},
|
||||||
|
"icons" : {
|
||||||
|
"android" : {
|
||||||
|
"hdpi" : "unpackage/res/icons/72x72.png",
|
||||||
|
"xhdpi" : "unpackage/res/icons/96x96.png",
|
||||||
|
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
||||||
|
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
||||||
|
},
|
||||||
|
"ios" : {
|
||||||
|
"appstore" : "unpackage/res/icons/1024x1024.png",
|
||||||
|
"ipad" : {
|
||||||
|
"app" : "unpackage/res/icons/76x76.png",
|
||||||
|
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||||
|
"notification" : "unpackage/res/icons/20x20.png",
|
||||||
|
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||||
|
"proapp@2x" : "unpackage/res/icons/167x167.png",
|
||||||
|
"settings" : "unpackage/res/icons/29x29.png",
|
||||||
|
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||||
|
"spotlight" : "unpackage/res/icons/40x40.png",
|
||||||
|
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||||
|
},
|
||||||
|
"iphone" : {
|
||||||
|
"app@2x" : "unpackage/res/icons/120x120.png",
|
||||||
|
"app@3x" : "unpackage/res/icons/180x180.png",
|
||||||
|
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||||
|
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||||
|
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||||
|
"settings@3x" : "unpackage/res/icons/87x87.png",
|
||||||
|
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
||||||
|
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quickapp" : {},
|
||||||
|
"mp-weixin" : {
|
||||||
|
"appid" : "wxabb93d365d4475a4",
|
||||||
|
"setting" : {
|
||||||
|
"urlCheck" : false
|
||||||
|
},
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-alipay" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-baidu" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-toutiao" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"h5" : {
|
||||||
|
"router" : {
|
||||||
|
"base" : "./",
|
||||||
|
"mode" : "hash"
|
||||||
|
},
|
||||||
|
"template" : "h5.template.html",
|
||||||
|
"optimization" : {
|
||||||
|
"treeShaking" : {
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vueVersion" : "3"
|
||||||
|
}
|
20
package.json
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-template-news",
|
||||||
|
"name": "新闻资讯App模板",
|
||||||
|
"displayName": "新闻资讯App模板",
|
||||||
|
"version": "3.1.7",
|
||||||
|
"description": "基于uni-app开发的新闻/资讯类App模板",
|
||||||
|
"keywords": [
|
||||||
|
"模板",
|
||||||
|
"新闻",
|
||||||
|
"资讯",
|
||||||
|
"nvue",
|
||||||
|
"新闻模板"
|
||||||
|
],
|
||||||
|
"dcloudext": {
|
||||||
|
"category": [
|
||||||
|
"前端页面模板",
|
||||||
|
"uni-app前端项目模板"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
32
pages.json
Normal file
32
pages.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"pages": [{
|
||||||
|
"path": "pages/news/index",
|
||||||
|
"style": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/news/detail",
|
||||||
|
"style": {
|
||||||
|
"app-plus": {
|
||||||
|
"titleNView": {
|
||||||
|
"type": "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarTitleText": "新闻资讯",
|
||||||
|
"navigationBarBackgroundColor": "#2F85FC",
|
||||||
|
"backgroundColor": "#FFFFFF"
|
||||||
|
},
|
||||||
|
"rightWindow": {
|
||||||
|
"path": "responsive/right-window.vue",
|
||||||
|
"style": {
|
||||||
|
"width": "calc(100vw - 450px)"
|
||||||
|
},
|
||||||
|
"matchMedia": {
|
||||||
|
"minWidth": 768
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
pages/news/detail.nvue
Normal file
178
pages/news/detail.nvue
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<view class="banner" auto-focus>
|
||||||
|
<image class="banner-img" :src="banner.image_url"></image>
|
||||||
|
<view class="title-area">
|
||||||
|
<text class="title-text">{{banner.title}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="article-meta">
|
||||||
|
<text class="article-meta-text article-author">{{banner.source}}</text>
|
||||||
|
<text class="article-meta-text article-text">发表于</text>
|
||||||
|
<text class="article-meta-text article-time">{{banner.datetime}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="article-content">
|
||||||
|
<rich-text :nodes="content" style="font-size: 14px;"></rich-text>
|
||||||
|
</view>
|
||||||
|
<view class="comment-wrap"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import htmlParser from '../../common/html-parser'
|
||||||
|
|
||||||
|
const FAIL_CONTENT = '<p>获取信息失败1</p>';
|
||||||
|
|
||||||
|
function parseImgs(nodes) {
|
||||||
|
nodes.forEach(node => {
|
||||||
|
if (
|
||||||
|
node.name === 'img' &&
|
||||||
|
node.attrs &&
|
||||||
|
node.attrs['data-img-size-val']
|
||||||
|
) {
|
||||||
|
const sizes = node.attrs['data-img-size-val'].split(',')
|
||||||
|
const width = uni.upx2px(720 * 0.9)
|
||||||
|
const height = parseInt(width * (sizes[1] / sizes[0]))
|
||||||
|
node.attrs.style = `width:${width};height:${height};`
|
||||||
|
}
|
||||||
|
if (Array.isArray(node.children)) {
|
||||||
|
parseImgs(node.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
banner: {},
|
||||||
|
content: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShareAppMessage() {
|
||||||
|
return {
|
||||||
|
title: this.banner.title,
|
||||||
|
path: '/pages/detail/detail?query=' + JSON.stringify(this.banner)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(event) {
|
||||||
|
// 目前在某些平台参数会被主动 decode,暂时这样处理。
|
||||||
|
|
||||||
|
this.load(event.query);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
load(e) {
|
||||||
|
var p = decodeURIComponent(e);
|
||||||
|
try {
|
||||||
|
this.banner = JSON.parse(p);
|
||||||
|
} catch (error) {
|
||||||
|
this.banner = JSON.parse(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: this.banner.title
|
||||||
|
});
|
||||||
|
|
||||||
|
this.getDetail();
|
||||||
|
},
|
||||||
|
getDetail() {
|
||||||
|
uni.request({
|
||||||
|
url: 'https://unidemo.dcloud.net.cn/api/news/36kr/' + this.banner.post_id,
|
||||||
|
success: (result) => {
|
||||||
|
let content = FAIL_CONTENT
|
||||||
|
if (result.statusCode == 200) {
|
||||||
|
content = result.data.content
|
||||||
|
}
|
||||||
|
const nodes = htmlParser(content);
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
parseImgs(nodes)
|
||||||
|
// #endif
|
||||||
|
this.content = nodes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
page {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
height: 180px;
|
||||||
|
position: relative;
|
||||||
|
background-color: #ccc;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-img {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-area {
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 15px;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
lines: 2;
|
||||||
|
color: #ffffff;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta {
|
||||||
|
padding: 10px 15px;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta-text {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-text {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 25px;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-author {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-time {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 0 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef H5 */
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
381
pages/news/index.nvue
Normal file
381
pages/news/index.nvue
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
<template>
|
||||||
|
<view class="tabs">
|
||||||
|
<scroll-view ref="tabbar1" id="tab-bar" class="tab-bar" :scroll="false" :scroll-x="true" :show-scrollbar="false"
|
||||||
|
:scroll-into-view="scrollInto" :enable-flex="true">
|
||||||
|
<view style="flex-direction: column;">
|
||||||
|
<view style="flex-direction: row;">
|
||||||
|
<view class="uni-tab-item" v-for="(tab,index) in tabList" :key="tab.newsid" :id="tab.newsid" :ref="'tabitem'+tab.newsid"
|
||||||
|
:data-id="index" :data-current="index" @click="ontabtap">
|
||||||
|
<text class="uni-tab-item-title" :class="tabIndex==index ? 'uni-tab-item-title-active' : ''">{{tab.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="scroll-view-indicator">
|
||||||
|
<view ref="underline" class="scroll-view-underline" :class="isTap ? 'scroll-view-animation':''" :style="{left: indicatorLineLeft + 'px', width: indicatorLineWidth + 'px'}"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="tab-bar-line"></view>
|
||||||
|
<swiper class="tab-box" ref="swiper1" :current="tabIndex" :duration="300" @change="onswiperchange" @transition="onswiperscroll"
|
||||||
|
@animationfinish="animationfinish" @onAnimationEnd="animationfinish">
|
||||||
|
<swiper-item class="swiper-item" v-for="(page, index) in tabList" :key="index">
|
||||||
|
<newsPage class="page-item" :nid="page.newsid" :ref="'page' + index"></newsPage>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const dom = weex.requireModule('dom');
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
import newsPage from './news-page.nvue';
|
||||||
|
|
||||||
|
// 缓存每页最多
|
||||||
|
const MAX_CACHE_DATA = 100;
|
||||||
|
// 缓存页签数量
|
||||||
|
const MAX_CACHE_PAGE = 3;
|
||||||
|
const TAB_PRELOAD_OFFSET = 1;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
newsPage
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabList: [{
|
||||||
|
name: '互联网',
|
||||||
|
newsid: 34
|
||||||
|
}, {
|
||||||
|
name: 'IT',
|
||||||
|
newsid: 22
|
||||||
|
}, {
|
||||||
|
name: '科技',
|
||||||
|
newsid: 13
|
||||||
|
}, {
|
||||||
|
name: '苹果',
|
||||||
|
newsid: 19
|
||||||
|
}, {
|
||||||
|
name: '旅游',
|
||||||
|
newsid: 18
|
||||||
|
}, {
|
||||||
|
name: '影视',
|
||||||
|
newsid: 40
|
||||||
|
}, {
|
||||||
|
name: '汽车',
|
||||||
|
newsid: 35
|
||||||
|
}, {
|
||||||
|
name: '动漫',
|
||||||
|
newsid: 33
|
||||||
|
}, {
|
||||||
|
name: '游戏',
|
||||||
|
newsid: 31
|
||||||
|
}, {
|
||||||
|
name: '军事',
|
||||||
|
newsid: 27
|
||||||
|
}],
|
||||||
|
tabIndex: 0,
|
||||||
|
cacheTab: [],
|
||||||
|
scrollInto: "",
|
||||||
|
navigateFlag: false,
|
||||||
|
indicatorLineLeft: 0,
|
||||||
|
indicatorLineWidth: 0,
|
||||||
|
isTap: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this._lastTabIndex = 0;
|
||||||
|
this.swiperWidth = 0;
|
||||||
|
this.tabbarWidth = 0;
|
||||||
|
this.tabListSize = {};
|
||||||
|
this._touchTabIndex = 0;
|
||||||
|
|
||||||
|
this.pageList = [];
|
||||||
|
for (var i = 0; i < this.tabList.length; i++) {
|
||||||
|
let item = this.$refs['page' + i]
|
||||||
|
if (Array.isArray(item)) {
|
||||||
|
this.pageList.push(item[0])
|
||||||
|
} else {
|
||||||
|
this.pageList.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.switchTab(this.tabIndex);
|
||||||
|
|
||||||
|
this.selectorQuery();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
ontabtap(e) {
|
||||||
|
let index = e.target.dataset.current || e.currentTarget.dataset.current;
|
||||||
|
//let offsetIndex = this._touchTabIndex = Math.abs(index - this._lastTabIndex) > 1;
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-QQ
|
||||||
|
this.isTap = true;
|
||||||
|
var currentSize = this.tabListSize[index];
|
||||||
|
this.updateIndicator(currentSize.left, currentSize.width);
|
||||||
|
this._touchTabIndex = index;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
this.switchTab(index);
|
||||||
|
},
|
||||||
|
onswiperchange(e) {
|
||||||
|
// 注意:百度小程序会触发2次
|
||||||
|
|
||||||
|
// #ifndef APP-PLUS || H5 || MP-WEIXIN || MP-QQ
|
||||||
|
let index = e.target.current || e.detail.current;
|
||||||
|
this.switchTab(index);
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
onswiperscroll(e) {
|
||||||
|
if (this.isTap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var offsetX = e.detail.dx;
|
||||||
|
var preloadIndex = this._lastTabIndex;
|
||||||
|
if (offsetX > TAB_PRELOAD_OFFSET) {
|
||||||
|
preloadIndex++;
|
||||||
|
} else if (offsetX < -TAB_PRELOAD_OFFSET) {
|
||||||
|
preloadIndex--;
|
||||||
|
}
|
||||||
|
if (preloadIndex === this._lastTabIndex || preloadIndex < 0 || preloadIndex > this.pageList.length - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.pageList[preloadIndex].dataList.length === 0) {
|
||||||
|
this.loadTabData(preloadIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-QQ
|
||||||
|
var percentage = Math.abs(this.swiperWidth / offsetX);
|
||||||
|
var currentSize = this.tabListSize[this._lastTabIndex];
|
||||||
|
var preloadSize = this.tabListSize[preloadIndex];
|
||||||
|
var lineL = currentSize.left + (preloadSize.left - currentSize.left) / percentage;
|
||||||
|
var lineW = currentSize.width + (preloadSize.width - currentSize.width) / percentage;
|
||||||
|
this.updateIndicator(lineL, lineW);
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
animationfinish(e) {
|
||||||
|
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-QQ
|
||||||
|
let index = e.detail.current;
|
||||||
|
if (this._touchTabIndex === index) {
|
||||||
|
this.isTap = false;
|
||||||
|
}
|
||||||
|
this._lastTabIndex = index;
|
||||||
|
this.switchTab(index);
|
||||||
|
this.updateIndicator(this.tabListSize[index].left, this.tabListSize[index].width);
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
selectorQuery() {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
dom.getComponentRect(this.$refs.tabbar1, res => {
|
||||||
|
this.tabbarWidth = res.size.width;
|
||||||
|
});
|
||||||
|
dom.getComponentRect(this.$refs['swiper1'], res => {
|
||||||
|
this.swiperWidth = res.size.width;
|
||||||
|
});
|
||||||
|
// for (var i = 0; i < this.tabList.length; i++) {
|
||||||
|
// this.getElementSize(dom, this.$refs['tabitem' + i][0], i);
|
||||||
|
// }
|
||||||
|
// 因 nvue 暂不支持 class 查询
|
||||||
|
var queryTabSize = uni.createSelectorQuery().in(this);
|
||||||
|
for (var i = 0; i < this.tabList.length; i++) {
|
||||||
|
queryTabSize.select('#' + this.tabList[i].newsid).boundingClientRect();
|
||||||
|
}
|
||||||
|
queryTabSize.exec(rects => {
|
||||||
|
rects.forEach((rect) => {
|
||||||
|
this.tabListSize[rect.dataset.id] = rect;
|
||||||
|
})
|
||||||
|
this.updateIndicator(this.tabListSize[this.tabIndex].left, this.tabListSize[this.tabIndex].width);
|
||||||
|
this.switchTab(this.tabIndex);
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN || H5 || MP-QQ
|
||||||
|
uni.createSelectorQuery().in(this).select('.tab-box').fields({
|
||||||
|
dataset: true,
|
||||||
|
size: true,
|
||||||
|
}, (res) => {
|
||||||
|
this.swiperWidth = res.width;
|
||||||
|
}).exec();
|
||||||
|
uni.createSelectorQuery().in(this).selectAll('.uni-tab-item').boundingClientRect((rects) => {
|
||||||
|
rects.forEach((rect) => {
|
||||||
|
this.tabListSize[rect.dataset.id] = rect;
|
||||||
|
})
|
||||||
|
this.updateIndicator(this.tabListSize[this.tabIndex].left, this.tabListSize[this.tabIndex].width);
|
||||||
|
}).exec();
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
getElementSize(dom, ref, id) {
|
||||||
|
dom.getComponentRect(ref, res => {
|
||||||
|
this.tabListSize[id] = res.size;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateIndicator(left, width) {
|
||||||
|
this.indicatorLineLeft = left;
|
||||||
|
this.indicatorLineWidth = width;
|
||||||
|
},
|
||||||
|
switchTab(index) {
|
||||||
|
if (this.pageList[index].dataList.length === 0) {
|
||||||
|
this.loadTabData(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.tabIndex === index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存 tabId
|
||||||
|
if (this.pageList[this.tabIndex].dataList.length > MAX_CACHE_DATA) {
|
||||||
|
let isExist = this.cacheTab.indexOf(this.tabIndex);
|
||||||
|
if (isExist < 0) {
|
||||||
|
this.cacheTab.push(this.tabIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tabIndex = index;
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
this.scrollTabTo(index);
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
this.scrollInto = "tab" + this.tabList[index].newsid;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 释放 tabId
|
||||||
|
if (this.cacheTab.length > MAX_CACHE_PAGE) {
|
||||||
|
let cacheIndex = this.cacheTab[0];
|
||||||
|
this.clearTabData(cacheIndex);
|
||||||
|
this.cacheTab.splice(0, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollTabTo(index) {
|
||||||
|
const el = this.$refs['tabitem' + index][0];
|
||||||
|
let offset = 0;
|
||||||
|
// TODO fix ios offset
|
||||||
|
if (index > 0) {
|
||||||
|
offset = this.tabbarWidth / 2 - this.tabListSize[index].width / 2;
|
||||||
|
if (this.tabListSize[index].right < this.tabbarWidth / 2) {
|
||||||
|
offset = this.tabListSize[0].width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dom.scrollToElement(el, {
|
||||||
|
offset: -offset
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadTabData(index) {
|
||||||
|
this.pageList[index].loadData();
|
||||||
|
},
|
||||||
|
clearTabData(index) {
|
||||||
|
this.pageList[index].clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
page {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #ffffff;
|
||||||
|
/* #ifdef MP-ALIPAY || MP-BAIDU */
|
||||||
|
height: 100vh;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-bar {
|
||||||
|
/* #ifdef APP-PLUS */
|
||||||
|
width: 750rpx;
|
||||||
|
/* #endif */
|
||||||
|
height: 42px;
|
||||||
|
flex-direction: row;
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
white-space: nowrap;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.tab-bar ::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.scroll-view-indicator {
|
||||||
|
position: relative;
|
||||||
|
height: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-view-underline {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 0;
|
||||||
|
background-color: #007AFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-view-animation {
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-property: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-bar-line {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-box {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-tab-item {
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
display: inline-block;
|
||||||
|
/* #endif */
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-tab-item-title {
|
||||||
|
color: #555;
|
||||||
|
font-size: 15px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
white-space: nowrap;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-tab-item-title-active {
|
||||||
|
color: #007AFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-item {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
198
pages/news/news-item.nvue
Normal file
198
pages/news/news-item.nvue
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
<template>
|
||||||
|
<view class="media-item view" @click="click">
|
||||||
|
<view class="view"
|
||||||
|
:style="{flexDirection: (newsItem.article_type === 1 || newsItem.article_type === 2)?(newsItem.article_type === 2 ?'row':'row-reverse'):'column' }">
|
||||||
|
<text class="media-title"
|
||||||
|
:class="{'media-title2': newsItem.article_type === 1 || newsItem.article_type === 2}">{{newsItem.title}}</text>
|
||||||
|
<view v-if="newsItem.image_list || newsItem.image_url" class="image-section flex-row"
|
||||||
|
:class="{'image-section-right': newsItem.article_type === 2, 'image-section-left': newsItem.article_type === 1}">
|
||||||
|
<image :fade-show="false" class="image-list1"
|
||||||
|
:class="{'image-list2': newsItem.article_type === 1 || newsItem.article_type === 2}"
|
||||||
|
v-if="newsItem.image_url" :src="newsItem.image_url"></image>
|
||||||
|
<template v-if="newsItem.image_list">
|
||||||
|
<image :fade-show="false" class="image-list3" :src="source.url"
|
||||||
|
v-for="(source, i) in newsItem.image_list" :key="i" />
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="media-foot flex-row">
|
||||||
|
<view class="media-info flex-row">
|
||||||
|
<text class="info-text">{{newsItem.source}}</text>
|
||||||
|
<text class="info-text">{{newsItem.comment_count}}条评论</text>
|
||||||
|
<text class="info-text">{{newsItem.datetime}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="close-view" @click.stop="close">
|
||||||
|
<view class="close-l close-h"></view>
|
||||||
|
<view class="close-l close-v"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="media-item-line" style="position: absolute;"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
newsItem: {
|
||||||
|
type: Object,
|
||||||
|
default: function(e) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
close(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.view {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-list-cell-hover {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-item {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px 15px 10px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-item-line {
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 0;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #ebebeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-image-right {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-image-left {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-title {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-title {
|
||||||
|
lines: 3;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #555555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-title2 {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 3px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-section {
|
||||||
|
margin-top: 10px;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-section-right {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
width: 112px;
|
||||||
|
height: 73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-section-left {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 112px;
|
||||||
|
height: 73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-list1 {
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-list2 {
|
||||||
|
width: 112px;
|
||||||
|
height: 73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-list3 {
|
||||||
|
width: 112px;
|
||||||
|
height: 73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-info {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-text {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #999999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-foot {
|
||||||
|
margin-top: 12px;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-view {
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 20px;
|
||||||
|
height: 15px;
|
||||||
|
line-height: 15px;
|
||||||
|
border-width: 1upx;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #aaaaaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-l {
|
||||||
|
position: absolute;
|
||||||
|
width: 9px;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-h {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-v {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
</style>
|
316
pages/news/news-page.nvue
Normal file
316
pages/news/news-page.nvue
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page-news">
|
||||||
|
<!-- #ifdef APP-NVUE -->
|
||||||
|
<list class="listview">
|
||||||
|
<refresh :display="refreshing" @refresh="onrefresh" @pullingdown="onpullingdown"></refresh>
|
||||||
|
<cell v-for="(item, index) in dataList" :key="item.newsid">
|
||||||
|
<news-item :newsItem="item" @close="closeItem(index)" @click="goDetail(item)"></news-item>
|
||||||
|
</cell>
|
||||||
|
<cell v-if="isLoading || dataList.length > 4">
|
||||||
|
<view class="loading-more">
|
||||||
|
<text class="loading-more-text">{{loadingText}}</text>
|
||||||
|
</view>
|
||||||
|
</cell>
|
||||||
|
</list>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef APP-NVUE -->
|
||||||
|
<scroll-view class="listview" style="flex: 1;" enableBackToTop="true" scroll-y @scrolltolower="loadMore()">
|
||||||
|
<view v-for="(item, index) in dataList" :key="item.newsid">
|
||||||
|
<news-item :newsItem="item" @close="closeItem(index)" @click="goDetail(item)"></news-item>
|
||||||
|
</view>
|
||||||
|
<view class="loading-more" v-if="isLoading || dataList.length > 4">
|
||||||
|
<text class="loading-more-text">{{loadingText}}</text>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<no-data class="no-data" v-if="isNoData" @retry="loadMore"></no-data>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
friendlyDate
|
||||||
|
} from '@/common/util.js';
|
||||||
|
|
||||||
|
import newsItem from './news-item.nvue';
|
||||||
|
import uniLoadMore from '@/components/uni-load-more.vue';
|
||||||
|
import noData from '@/components/nodata.nvue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
uniLoadMore,
|
||||||
|
noData,
|
||||||
|
newsItem
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
nid: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dataList: [],
|
||||||
|
navigateFlag: false,
|
||||||
|
pulling: false,
|
||||||
|
refreshing: false,
|
||||||
|
refreshFlag: false,
|
||||||
|
refreshText: "",
|
||||||
|
isLoading: false,
|
||||||
|
loadingText: '加载中...',
|
||||||
|
isNoData: false,
|
||||||
|
pulling: false,
|
||||||
|
angle: 0,
|
||||||
|
loadingMoreText: {
|
||||||
|
contentdown: '',
|
||||||
|
contentrefresh: '',
|
||||||
|
contentnomore: ''
|
||||||
|
},
|
||||||
|
refreshIcon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAB5QTFRFcHBw3Nzct7e39vb2ycnJioqK7e3tpqam29vb////D8oK7wAAAAp0Uk5T////////////ALLMLM8AAABxSURBVHja7JVBDoAgDASrjqj//7CJBi90iyYeOHTPMwmFZrHjYyyFYYUy1bwUZqtJIYVxhf1a6u0R7iUvWsCcrEtwJHp8MwMdvh2amHduiZD3rpWId9+BgPd7Cc2LIkPyqvlQvKxKBJ//Qwq/CacAAwDUv0a0YuKhzgAAAABJRU5ErkJggg=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.pullTimer = null;
|
||||||
|
this.requestParams = {
|
||||||
|
key: 'c65b090e6589cc2c07e873c4a4ea60fd',
|
||||||
|
num: 50,
|
||||||
|
col: this.nid,
|
||||||
|
page: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
this._isWidescreen = false;
|
||||||
|
// #ifdef H5
|
||||||
|
var mediaQueryOb = uni.createMediaQueryObserver(this)
|
||||||
|
mediaQueryOb.observe({
|
||||||
|
minWidth: 768
|
||||||
|
}, matches => {
|
||||||
|
this._isWidescreen = matches;
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadData(refresh) {
|
||||||
|
if (this.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
this.isNoData = false;
|
||||||
|
|
||||||
|
var startTime = new Date();
|
||||||
|
uni.request({
|
||||||
|
// url: this.$host + 'api/news',
|
||||||
|
url: 'https://apis.tianapi.com/allnews/index',
|
||||||
|
method: 'POST',
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
data: this.requestParams,
|
||||||
|
success: (result) => {
|
||||||
|
var endTime = new Date();
|
||||||
|
const data = result.data.result.newslist;
|
||||||
|
this.isNoData = (data.length <= 0);
|
||||||
|
|
||||||
|
const data_list = data.map((news) => {
|
||||||
|
return {
|
||||||
|
id: this.newGuid() + news.newsid,
|
||||||
|
newsid: news.newsid,
|
||||||
|
article_type: 1,
|
||||||
|
datetime: friendlyDate(new Date(news.ctime.replace(/\-/g, '/'))
|
||||||
|
.getTime()),
|
||||||
|
title: news.title,
|
||||||
|
image_url: news.picUrl,
|
||||||
|
source: news.source
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
|
this.dataList = data_list;
|
||||||
|
} else {
|
||||||
|
this.dataList = this.dataList.concat(data_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dataList.length > 0 && this._isWidescreen && this.dataList.length <= 50) {
|
||||||
|
this.goDetail(this.dataList[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
if (this.dataList.length == 0) {
|
||||||
|
this.isNoData = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: (e) => {
|
||||||
|
this.isLoading = false;
|
||||||
|
if (refresh) {
|
||||||
|
this.refreshing = false;
|
||||||
|
this.refreshFlag = false;
|
||||||
|
this.refreshText = "已刷新";
|
||||||
|
if (this.pullTimer) {
|
||||||
|
clearTimeout(this.pullTimer);
|
||||||
|
}
|
||||||
|
this.pullTimer = setTimeout(() => {
|
||||||
|
this.pulling = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadMore(e) {
|
||||||
|
this.requestParams.page = this.requestParams.page + 1
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.dataList.length = 0;
|
||||||
|
},
|
||||||
|
goDetail(detail) {
|
||||||
|
if (this._isWidescreen) { //若为宽屏,则触发右侧详情页的自定义事件
|
||||||
|
uni.$emit('updateDetail', {
|
||||||
|
detail: encodeURIComponent(JSON.stringify(detail))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: './detail?query=' + encodeURIComponent(JSON.stringify(detail))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeItem(index) {
|
||||||
|
uni.showModal({
|
||||||
|
content: '不感兴趣?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
this.dataList.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshData() {
|
||||||
|
if (this.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pulling = true;
|
||||||
|
this.refreshing = true;
|
||||||
|
this.refreshText = "正在刷新...";
|
||||||
|
this.loadData(true);
|
||||||
|
},
|
||||||
|
onrefresh(e) {
|
||||||
|
this.refreshData();
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
this.$refs.list.resetLoadmore();
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
onpullingdown(e) {
|
||||||
|
if (this.refreshing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pulling = false;
|
||||||
|
if (Math.abs(e.pullingDistance) > Math.abs(e.viewHeight)) {
|
||||||
|
this.refreshFlag = true;
|
||||||
|
this.refreshText = "释放立即刷新";
|
||||||
|
} else {
|
||||||
|
this.refreshFlag = false;
|
||||||
|
this.refreshText = "下拉可以刷新";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
newGuid() {
|
||||||
|
let s4 = function() {
|
||||||
|
return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
|
||||||
|
}
|
||||||
|
return (s4() + s4() + "-" + s4() + "-4" + s4().substr(0, 3) + "-" + s4() + "-" + s4() + s4() + s4())
|
||||||
|
.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.no-data {
|
||||||
|
flex: 1;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-news {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listview {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifndef MP-ALIPAY */
|
||||||
|
flex-direction: column;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-view {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
width: 750rpx;
|
||||||
|
height: 64px;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
transition-duration: .5s;
|
||||||
|
transition-property: transform;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
transform-origin: 15px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-icon-active {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-right: 5px;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-more {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 14px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-more-text {
|
||||||
|
font-size: 28upx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
188
pages/ucenter/ucenter.nvue
Normal file
188
pages/ucenter/ucenter.nvue
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<view class="center">
|
||||||
|
<view class="logo" @click="goLogin" :hover-class="!login ? 'logo-hover' : ''">
|
||||||
|
<image class="logo-img" :src="login ? uerInfo.avatarUrl :avatarUrl"></image>
|
||||||
|
<view class="logo-title">
|
||||||
|
<text class="uer-name">Hi,{{login ? uerInfo.name : '您未登录'}}</text>
|
||||||
|
<text class="go-login-navigat-arrow navigat-arrow" v-if="!login"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="center-list">
|
||||||
|
<view class="center-list-item border-bottom">
|
||||||
|
<text class="list-icon"></text>
|
||||||
|
<text class="list-text">账号管理</text>
|
||||||
|
<text class="navigat-arrow"></text>
|
||||||
|
</view>
|
||||||
|
<view class="center-list-item">
|
||||||
|
<text class="list-icon"></text>
|
||||||
|
<text class="list-text">新消息通知</text>
|
||||||
|
<text class="navigat-arrow"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="center-list">
|
||||||
|
<view class="center-list-item border-bottom">
|
||||||
|
<text class="list-icon"></text>
|
||||||
|
<text class="list-text">帮助与反馈</text>
|
||||||
|
<text class="navigat-arrow"></text>
|
||||||
|
</view>
|
||||||
|
<view class="center-list-item">
|
||||||
|
<text class="list-icon"></text>
|
||||||
|
<text class="list-text">服务条款及隐私</text>
|
||||||
|
<text class="navigat-arrow"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="center-list">
|
||||||
|
<view class="center-list-item">
|
||||||
|
<text class="list-icon"></text>
|
||||||
|
<text class="list-text">关于应用</text>
|
||||||
|
<text class="navigat-arrow"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
login: false,
|
||||||
|
avatarUrl: '/static/logo.png',
|
||||||
|
uerInfo: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
goLogin() {
|
||||||
|
if (!this.login) {
|
||||||
|
console.log('点击前往登录');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* #ifndef APP-PLUS-NVUE */
|
||||||
|
@font-face {
|
||||||
|
font-family: texticons;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url('~@/static/text-icon.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
page {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif*/
|
||||||
|
|
||||||
|
/* 解决头条小程序字体图标不显示问题,因为头条运行时自动插入了span标签,且有全局字体 */
|
||||||
|
/* #ifdef MP-TOUTIAO */
|
||||||
|
text :not(view) {
|
||||||
|
font-family: texticons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.center {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 750upx;
|
||||||
|
height: 240upx;
|
||||||
|
padding: 20upx;
|
||||||
|
background-color: #2F85FC;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-img {
|
||||||
|
width: 150upx;
|
||||||
|
height: 150upx;
|
||||||
|
border-radius: 150upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-title {
|
||||||
|
height: 150upx;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: 20upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uer-name {
|
||||||
|
height: 60upx;
|
||||||
|
line-height: 60upx;
|
||||||
|
font-size: 38upx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go-login-navigat-arrow {
|
||||||
|
font-size: 38upx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
height: 150upx;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: 20upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-list {
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
margin-top: 20upx;
|
||||||
|
width: 750upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-list-item {
|
||||||
|
height: 90upx;
|
||||||
|
width: 750upx;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0upx 20upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom {
|
||||||
|
border-bottom-width: 1upx;
|
||||||
|
border-color: #c8c7cc;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon {
|
||||||
|
width: 40upx;
|
||||||
|
height: 90upx;
|
||||||
|
line-height: 90upx;
|
||||||
|
font-size: 34upx;
|
||||||
|
color: #2F85FC;
|
||||||
|
text-align: center;
|
||||||
|
font-family: texticons;
|
||||||
|
margin-right: 20upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-text {
|
||||||
|
height: 90upx;
|
||||||
|
line-height: 90upx;
|
||||||
|
font-size: 34upx;
|
||||||
|
color: #555;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigat-arrow {
|
||||||
|
height: 90upx;
|
||||||
|
width: 40upx;
|
||||||
|
line-height: 90upx;
|
||||||
|
font-size: 34upx;
|
||||||
|
color: #555;
|
||||||
|
text-align: right;
|
||||||
|
font-family: texticons;
|
||||||
|
}
|
||||||
|
</style>
|
29
responsive/right-window.vue
Normal file
29
responsive/right-window.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<newDetail ref="detailPage"></newDetail>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import newDetail from '../pages/news/detail.nvue'
|
||||||
|
export default {
|
||||||
|
components:{
|
||||||
|
newDetail
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: 'Hello'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(e) {
|
||||||
|
//监听自定义事件,该事件由详情页列表的点击触发
|
||||||
|
uni.$on('updateDetail', (e) => {
|
||||||
|
// 执行 /pages/news/detail.nvue页面的load方法
|
||||||
|
this.$refs.detailPage.load(e.detail);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
BIN
static/app-icon.png
Normal file
BIN
static/app-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
static/center-active.png
Normal file
BIN
static/center-active.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
BIN
static/center.png
Normal file
BIN
static/center.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
static/home-active.png
Normal file
BIN
static/home-active.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
static/home.png
Normal file
BIN
static/home.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
static/logo.png
Normal file
BIN
static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
static/text-icon.ttf
Normal file
BIN
static/text-icon.ttf
Normal file
Binary file not shown.
76
uni.scss
Normal file
76
uni.scss
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* 这里是uni-app内置的常用样式变量
|
||||||
|
*
|
||||||
|
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||||
|
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||||
|
*
|
||||||
|
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 颜色变量 */
|
||||||
|
|
||||||
|
/* 行为相关颜色 */
|
||||||
|
$uni-color-primary: #007aff;
|
||||||
|
$uni-color-success: #4cd964;
|
||||||
|
$uni-color-warning: #f0ad4e;
|
||||||
|
$uni-color-error: #dd524d;
|
||||||
|
|
||||||
|
/* 文字基本颜色 */
|
||||||
|
$uni-text-color:#333;//基本色
|
||||||
|
$uni-text-color-inverse:#fff;//反色
|
||||||
|
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||||
|
$uni-text-color-placeholder: #808080;
|
||||||
|
$uni-text-color-disable:#c0c0c0;
|
||||||
|
|
||||||
|
/* 背景颜色 */
|
||||||
|
$uni-bg-color:#ffffff;
|
||||||
|
$uni-bg-color-grey:#f8f8f8;
|
||||||
|
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||||
|
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||||
|
|
||||||
|
/* 边框颜色 */
|
||||||
|
$uni-border-color:#c8c7cc;
|
||||||
|
|
||||||
|
/* 尺寸变量 */
|
||||||
|
|
||||||
|
/* 文字尺寸 */
|
||||||
|
$uni-font-size-sm:24upx;
|
||||||
|
$uni-font-size-base:28upx;
|
||||||
|
$uni-font-size-lg:32upx;
|
||||||
|
|
||||||
|
/* 图片尺寸 */
|
||||||
|
$uni-img-size-sm:40upx;
|
||||||
|
$uni-img-size-base:52upx;
|
||||||
|
$uni-img-size-lg:80upx;
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
$uni-border-radius-sm: 4upx;
|
||||||
|
$uni-border-radius-base: 6upx;
|
||||||
|
$uni-border-radius-lg: 12upx;
|
||||||
|
$uni-border-radius-circle: 50%;
|
||||||
|
|
||||||
|
/* 水平间距 */
|
||||||
|
$uni-spacing-row-sm: 10px;
|
||||||
|
$uni-spacing-row-base: 20upx;
|
||||||
|
$uni-spacing-row-lg: 30upx;
|
||||||
|
|
||||||
|
/* 垂直间距 */
|
||||||
|
$uni-spacing-col-sm: 8upx;
|
||||||
|
$uni-spacing-col-base: 16upx;
|
||||||
|
$uni-spacing-col-lg: 24upx;
|
||||||
|
|
||||||
|
/* 透明度 */
|
||||||
|
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||||
|
|
||||||
|
/* 文章场景相关 */
|
||||||
|
$uni-color-title: #2C405A; // 文章标题颜色
|
||||||
|
$uni-font-size-title:40upx;
|
||||||
|
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||||
|
$uni-font-size-subtitle:36upx;
|
||||||
|
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||||
|
$uni-font-size-paragraph:30upx;
|
Loading…
Reference in New Issue
Block a user