未验证 提交 5a43a5fc 编写于 作者: hbcui1984's avatar hbcui1984 提交者: GitHub

Merge pull request #28 from zhetengbiji/master

增项mpvue项目移植示例:「ONE · 一个」
<script>
import { mapActions, mapMutations } from 'vuex'
export default {
created () {
this.initPage()
},
methods: {
...mapMutations('weather', {
setLocation: 'SET_LOCATION'
}),
...mapActions('weather', ['getWeather']),
async initPage() {
const location = await this.getLocation()
this.setLocation({
location
})
this.getWeather()
},
async getLocation() {
return await new Promise((resolve, reject) => {
wx.getLocation({
success(location) {
resolve(location)
},
fail(err) {
console.log(err)
reject(err)
}
})
})
}
}
}
</script>
<style>
.container {
font-size: 26rpx;
text-align: center;
}
.wrapper {
font-size: 26rpx;
text-align: left;
}
* {
transition: width 2s;
-moz-transition: width 2s;
-webkit-transition: width 2s;
-o-transition: width 2s;
}
/* font color */
* {
color: #353535;
}
.gray {
color: #808080;
}
.wxParse {
text-indent: 2em;
}
.wxParse image {
text-indent: 0;
}
.wxParse ._view {
padding: 0 10rpx;
text-indent: 0;
}
.wxParse .p {
text-indent: 1em;
}
</style>
# uni-one
> 使用uni-app开发的 [「ONE · 一个」](http://wufazhuce.com)
> 移植自[mpvue-one](https://github.com/feng-fu/mpvue-one/blob/master/README.md)
> 本项目仅作为mpvue项目移植示例
## 使用方式
将项目拖入[HbuildX](http://www.dcloud.io/hbuilderx.html),直接运行即可
## 注意事项
* 在小程序中预览提示合法域名校验出错,需打开微信开发者工具内 设置-项目设置,勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。
\ No newline at end of file
<template>
<block>
<view class="title">
<text>{{title}}</text>
</view>
<view class="author" v-if="user_name">
<text>文 / {{user_name}}</text>
</view>
<view class="summary" v-if="summary">
<view class="line"></view>
<text>{{summary}}</text>
</view>
<wx-parse :content="content"></wx-parse>
</block>
</template>
<script>
import wxParse from './mpvue-wxparse/wxParse.vue'
export default {
props: {
title: String,
user_name: String,
content: String,
summary: String
},
components: {
wxParse
}
}
</script>
<style scoped>
.title {
font-size: 36rpx;
font-weight: 700;
margin: .8em .8em;
text-align: center;
}
.author {
color: #cacaca;
font-size: 24rpx;
text-align: right;
padding-right: 2em;
}
.summary {
position: relative;
color: #b0b0b0;
font-size: 24rpx;
white-space: nowrap;
text-overflow: ellipse;
padding-left: 40rpx;
height: 60rpx;
line-height: 60rpx;
}
.summary .line {
position: absolute;
top: 14rpx;
left: 20rpx;
width: 10rpx;
height: 32rpx;
background-color: #d0d0d0;
}
</style>
<template>
<block>
<view class="list-container" v-if="movie.subtitle">
<view class="content">
<view class="view-title title">
<text>{{movie.title}}</text>
</view>
<view class="author">
<!-- <text>{{movie.author_list[0].user_name}} —— </text> -->
<!-- <text>{{movie.author_list[0].desc}}</text> -->
<text>{{movie.subtitle}}</text>
</view>
</view>
<view>
<image class="avatar" :src="movie.img_url || 'https://petrify.oss-cn-beijing.aliyuncs.com/arrow-right.png'" />
</view>
</view>
<block v-else>
<view class="only-title title">
<text>{{movie.title}}</text>
<image class="arraw" src="https://petrify.oss-cn-beijing.aliyuncs.com/arrow-right.png" />
</view>
</block>
</block>
</template>
<script>
export default {
props: {
movie: Object
}
}
</script>
<style>
.title {
font-size: 28rpx;
line-height: 40rpx;
margin-bottom: 10rpx;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.only-title {
height: 100%;
line-height: 170rpx;
text-align: left;
padding-left: 20rpx;
display: flex;
align-items: center;
}
.only-title text {
width: 680rpx;
}
.arraw {
width: 28rpx;
height: 28rpx;
}
.view-title {
text-align: left;
}
.avatar {
width: 100rpx;
height: 100rpx;
padding-right: 20rpx;
}
.list-container {
display: flex;
align-items: center;
height: 100%;
padding-left: 20rpx;
}
.content {
width: 600rpx;
}
.author {
text-align: left;
color: #979794;
}
</style>
<template>
<image
class="img"
:mode="node.image.mode"
:lazy-load="node.image.lazyLoad"
:class="node.classStr"
:style="fitStyleStr"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
@load="wxParseImgLoad"
/>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
realWindowWidth: 0,
realWindowHeight: 0,
newStyleStr: '',
};
},
props: {
node: {
type: Object,
default() {
return {};
},
},
},
mounted() {
this.getSysWH();
},
computed: {
fitStyleStr() {
return this.newStyleStr || this.node.styleStr;
},
},
methods: {
getSysWH() {
// 获取当前设备屏幕宽度和高度, 写在这里只是为了方便调试, 最好是写到 wxParse.vue 再传入
wx.getSystemInfo({
success: (res) => {
this.realWindowWidth = res.windowWidth;
this.realWindowHeight = res.windowHeight;
},
});
},
wxParseImgTap(e) {
const { src } = e.target.dataset;
if (!src) return;
wx.previewImage({
current: src, // 当前显示图片的http链接
urls: this.node.image.urls, // 需要预览的图片http链接列表
});
},
// 图片视觉宽高计算函数区
wxParseImgLoad(e) {
const { src } = e.target.dataset;
if (!src) return;
if (typeof src !== 'undefined' && src !== '' && src !== null) {
this.calMoreImageInfo(e);
}
},
// 假循环获取计算图片视觉最佳宽高
calMoreImageInfo(e) {
const { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding } = this.node.image;
this.newStyleStr = `height: ${imageheight}px; width: ${imageWidth}px; padding: 0 ${padding}px;`;
},
// 计算视觉优先的图片宽高
wxAutoImageCal(originalWidth, originalHeight) {
// 获取图片的原始长宽
const { padding } = this.node.image;
const windowWidth = this.realWindowWidth - (2 * padding);
const results = {};
// 判断按照那种方式进行缩放
if (originalWidth > windowWidth) {
// 在图片width大于手机屏幕width时候
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
// 否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
},
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--table类型-->
<block v-else-if="node.tag == 'table'">
<view :class="node.classStr" class="table" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate1';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate0',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
{{node.text}}
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
s<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" class="li" :style="node.styleStr">
<view :class="node.classStr" class="li-inner">
<view :class="node.classStr" class="li-text">
<view :class="node.classStr" class="li-circle"></view>
</view>
<view :class="node.classStr" class="li-text">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view :class="node.classStr" class="inline a" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他块级标签-->
<block v-else-if="node.tagType == 'block' && node.tag !== 'script'">
<view :class="[node.classStr, node.tag]" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--内联标签-->
<view v-else-if="node.tagType == 'inline' && node.tag !== 'style'" :class="[node.classStr, node.tag]" class="inline" :style="node.styleStr">
<block v-for="node of node.nodes" :key="node.index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">
{{node.text}}
</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
},
};
</script>
<template>
<!--增加video标签支持,并循环添加-->
<view :class="node.classStr" class="video" :style="node.styleStr">
<video :class="node.classStr" class="video-video" :src="node.attr.src"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
const placeImgeUrlHttps = 'https';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,a,code,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,ins,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
const inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,button,cite,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)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
return html
.replace(/<\?xml.*\\?>\n/, '')
.replace(/<.*!doctype.*\\>\n/, '')
.replace(/<.*!DOCTYPE.*\\>\n/, '');
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<');
}
function html2json(html, image, debug) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
images: [],
imageUrls: [],
};
let index = 0;
image.urls = results.imageUrls;
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = {
node: 'element',
tag,
};
if (bufArray.length === 0) {
node.index = index.toString();
index += 1;
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
node.index = `${parent.index}.${parent.nodes.length}`;
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
if (debug) console.dir(value);
// value = value.join("")
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
if (debug) console.dir(value);
// value = value.join("")
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 对img添加额外数据
if (node.tag === 'img') {
node.imgIndex = results.images.length;
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, placeImgeUrlHttps);
node.attr.src = imgUrl || '';
node.image = image;
if (imgUrl) {
results.images.push(node);
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.attr.style) node.attr.style = [];
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.attr.style.push(styleAttrs[key]);
node.attr.style.push(value);
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag && debug) {
console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
const node = {
node: 'text',
text: text.trim(),
};
if (bufArray.length === 0) {
node.index = index.toString();
index += 1;
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
node.index = `${parent.index}.${parent.nodes.length}`;
parent.nodes.push(node);
}
},
comment(text) {
const node = {
node: 'comment',
text,
};
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
},
});
return results;
}
export default html2json;
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('a,address,code,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,ins,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
const inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,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)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
// Special Elements (can contain anything)
const special = makeMap('script,style,view,scroll-view,block');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
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) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
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('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
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()}[^>]*>`),
(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 new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/&forall;/g, '');
str = str.replace(/&part;/g, '');
str = str.replace(/&exist;/g, '');
str = str.replace(/&empty;/g, '');
str = str.replace(/&nabla;/g, '');
str = str.replace(/&isin;/g, '');
str = str.replace(/&notin;/g, '');
str = str.replace(/&ni;/g, '');
str = str.replace(/&prod;/g, '');
str = str.replace(/&sum;/g, '');
str = str.replace(/&minus;/g, '');
str = str.replace(/&lowast;/g, '');
str = str.replace(/&radic;/g, '');
str = str.replace(/&prop;/g, '');
str = str.replace(/&infin;/g, '');
str = str.replace(/&ang;/g, '');
str = str.replace(/&and;/g, '');
str = str.replace(/&or;/g, '');
str = str.replace(/&cap;/g, '');
str = str.replace(/&cup;/g, '');
str = str.replace(/&int;/g, '');
str = str.replace(/&there4;/g, '');
str = str.replace(/&sim;/g, '');
str = str.replace(/&cong;/g, '');
str = str.replace(/&asymp;/g, '');
str = str.replace(/&ne;/g, '');
str = str.replace(/&le;/g, '');
str = str.replace(/&ge;/g, '');
str = str.replace(/&sub;/g, '');
str = str.replace(/&sup;/g, '');
str = str.replace(/&nsub;/g, '');
str = str.replace(/&sube;/g, '');
str = str.replace(/&supe;/g, '');
str = str.replace(/&oplus;/g, '');
str = str.replace(/&otimes;/g, '');
str = str.replace(/&perp;/g, '');
str = str.replace(/&sdot;/g, '');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/&Alpha;/g, 'Α');
str = str.replace(/&Beta;/g, 'Β');
str = str.replace(/&Gamma;/g, 'Γ');
str = str.replace(/&Delta;/g, 'Δ');
str = str.replace(/&Epsilon;/g, 'Ε');
str = str.replace(/&Zeta;/g, 'Ζ');
str = str.replace(/&Eta;/g, 'Η');
str = str.replace(/&Theta;/g, 'Θ');
str = str.replace(/&Iota;/g, 'Ι');
str = str.replace(/&Kappa;/g, 'Κ');
str = str.replace(/&Lambda;/g, 'Λ');
str = str.replace(/&Mu;/g, 'Μ');
str = str.replace(/&Nu;/g, 'Ν');
str = str.replace(/&Xi;/g, 'Ν');
str = str.replace(/&Omicron;/g, 'Ο');
str = str.replace(/&Pi;/g, 'Π');
str = str.replace(/&Rho;/g, 'Ρ');
str = str.replace(/&Sigma;/g, 'Σ');
str = str.replace(/&Tau;/g, 'Τ');
str = str.replace(/&Upsilon;/g, 'Υ');
str = str.replace(/&Phi;/g, 'Φ');
str = str.replace(/&Chi;/g, 'Χ');
str = str.replace(/&Psi;/g, 'Ψ');
str = str.replace(/&Omega;/g, 'Ω');
str = str.replace(/&alpha;/g, 'α');
str = str.replace(/&beta;/g, 'β');
str = str.replace(/&gamma;/g, 'γ');
str = str.replace(/&delta;/g, 'δ');
str = str.replace(/&epsilon;/g, 'ε');
str = str.replace(/&zeta;/g, 'ζ');
str = str.replace(/&eta;/g, 'η');
str = str.replace(/&theta;/g, 'θ');
str = str.replace(/&iota;/g, 'ι');
str = str.replace(/&kappa;/g, 'κ');
str = str.replace(/&lambda;/g, 'λ');
str = str.replace(/&mu;/g, 'μ');
str = str.replace(/&nu;/g, 'ν');
str = str.replace(/&xi;/g, 'ξ');
str = str.replace(/&omicron;/g, 'ο');
str = str.replace(/&pi;/g, 'π');
str = str.replace(/&rho;/g, 'ρ');
str = str.replace(/&sigmaf;/g, 'ς');
str = str.replace(/&sigma;/g, 'σ');
str = str.replace(/&tau;/g, 'τ');
str = str.replace(/&upsilon;/g, 'υ');
str = str.replace(/&phi;/g, 'φ');
str = str.replace(/&chi;/g, 'χ');
str = str.replace(/&psi;/g, 'ψ');
str = str.replace(/&omega;/g, 'ω');
str = str.replace(/&thetasym;/g, 'ϑ');
str = str.replace(/&upsih;/g, 'ϒ');
str = str.replace(/&piv;/g, 'ϖ');
str = str.replace(/&middot;/g, '·');
return str;
}
//
function strcharacterDiscode(str) {
// 加入常用解析
str = str.replace(/&nbsp;/g, ' ');
str = str.replace(/&quot;/g, "'");
str = str.replace(/&amp;/g, '&');
// str = str.replace(/&lt;/g, '‹');
// str = str.replace(/&gt;/g, '›');
str = str.replace(/&lt;/g, '<');
str = str.replace(/&gt;/g, '>');
str = str.replace(/&#8226;/g, '');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/&OElig;/g, 'Œ');
str = str.replace(/&oelig;/g, 'œ');
str = str.replace(/&Scaron;/g, 'Š');
str = str.replace(/&scaron;/g, 'š');
str = str.replace(/&Yuml;/g, 'Ÿ');
str = str.replace(/&fnof;/g, 'ƒ');
str = str.replace(/&circ;/g, 'ˆ');
str = str.replace(/&tilde;/g, '˜');
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, '');
str = str.replace(/&thinsp;/g, '');
str = str.replace(/&zwnj;/g, '');
str = str.replace(/&zwj;/g, '');
str = str.replace(/&lrm;/g, '');
str = str.replace(/&rlm;/g, '');
str = str.replace(/&ndash;/g, '');
str = str.replace(/&mdash;/g, '');
str = str.replace(/&lsquo;/g, '');
str = str.replace(/&rsquo;/g, '');
str = str.replace(/&sbquo;/g, '');
str = str.replace(/&ldquo;/g, '');
str = str.replace(/&rdquo;/g, '');
str = str.replace(/&bdquo;/g, '');
str = str.replace(/&dagger;/g, '');
str = str.replace(/&Dagger;/g, '');
str = str.replace(/&bull;/g, '');
str = str.replace(/&hellip;/g, '');
str = str.replace(/&permil;/g, '');
str = str.replace(/&prime;/g, '');
str = str.replace(/&Prime;/g, '');
str = str.replace(/&lsaquo;/g, '');
str = str.replace(/&rsaquo;/g, '');
str = str.replace(/&oline;/g, '');
str = str.replace(/&euro;/g, '');
str = str.replace(/&trade;/g, '');
str = str.replace(/&larr;/g, '');
str = str.replace(/&uarr;/g, '');
str = str.replace(/&rarr;/g, '');
str = str.replace(/&darr;/g, '');
str = str.replace(/&harr;/g, '');
str = str.replace(/&crarr;/g, '');
str = str.replace(/&lceil;/g, '');
str = str.replace(/&rceil;/g, '');
str = str.replace(/&lfloor;/g, '');
str = str.replace(/&rfloor;/g, '');
str = str.replace(/&loz;/g, '');
str = str.replace(/&spades;/g, '');
str = str.replace(/&clubs;/g, '');
str = str.replace(/&hearts;/g, '');
str = str.replace(/&diams;/g, '');
str = str.replace(/&#39;/g, "'");
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, rep) {
const patt1 = new RegExp('^//');
const result = patt1.test(url);
if (result) {
url = `${rep}:${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
.wxParse {
width: 100%;
font-family: Helvetica, sans-serif;
font-size: 28rpx;
color: #666;
line-height: 1.8;
}
view {
word-break: hyphenate;
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}
/*//标题 */
.wxParse .div {
margin: 0;
padding: 0;
}
.wxParse .h1 {
font-size: 2em;
margin: 0.67em 0;
}
.wxParse .h2 {
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3 {
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4 {
margin: 1.33em 0;
}
.wxParse .h5 {
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6 {
font-size: 0.67em;
margin: 2.33em 0;
}
.wxParse .h1,
.wxParse .h2,
.wxParse .h3,
.wxParse .h4,
.wxParse .h5,
.wxParse .h6,
.wxParse .b,
.wxParse .strong {
font-weight: bolder;
}
.wxParse .p {
margin: 1em 0;
}
.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
background: #f5f5f5;
padding: 16rpx;
white-space: pre-wrap;
}
.wxParse .big {
font-size: 1.17em;
}
.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}
.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}
.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}
/*wxparse-自定义个性化的css样式*/
/*增加video的css样式*/
.wxParse .strong,
.wxParse .s {
display: inline;
}
.wxParse .a {
color: deepskyblue;
word-break: break-all;
overflow: auto;
}
.wxParse .video {
text-align: center;
margin: 20rpx 0;
}
.wxParse .video-video {
width: 100%;
}
.wxParse .img {
width: 0;
height: 0;
max-width: 100%;
overflow: hidden;
}
.wxParse .blockquote {
margin: 10rpx 0;
padding: 20rpx 0 20rpx 20rpx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6rpx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .code {
display: inline;
background: #f5f5f5;
}
.wxParse .ul {
margin: 20rpx 10rpx;
}
.wxParse .li,
.wxParse .li-inner {
display: flex;
align-items: baseline;
margin: 10rpx 0;
}
.wxParse .li-text {
display: flex;
align-items: center;
line-height: 40rpx;
}
.wxParse .li-circle {
display: inline-flex;
width: 10rpx;
height: 10rpx;
background-color: #333;
margin-right: 10rpx;
border-radius: 50%;
position: relative;
top: -5rpx;
}
.wxParse .li-square {
display: inline-flex;
width: 10rpx;
height: 10rpx;
background-color: #333;
margin-right: 10rpx;
}
.wxParse .li-ring {
display: inline-flex;
width: 10rpx;
height: 10rpx;
border: 2rpx solid #333;
border-radius: 50%;
background-color: #fff;
margin-right: 10rpx;
}
.wxParse .table {
width: 100%;
border-top: 2rpx solid #e0e0e0;
}
.wxParse .thead,.wxParse .tfoot,.wxParse .tr {
display: flex;
flex-direction: row;
}
.wxParse .th,.wxParse .td {
display: flex;
width: 1160rpx;
overflow: auto;
}
.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParseText {
align-items: center;
}
.wxParse .tr {
width:100%;
display: flex;
border-right: 2rpx solid #e0e0e0;
border-bottom: 2rpx solid #e0e0e0;
}
.wxParse .th,
.wxParse .td {
flex: 1;
padding: 10rpx;
border-left: 2rpx solid #e0e0e0;
word-break: break-all;
}
.wxParse .td:last {
border-top: 2rpx solid #e0e0e0;
}
.wxParse .th {
background: #f0f0f0;
border-top: 2rpx solid #e0e0e0;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
<!--**
* author: F-loat <chaimaoyuan@foxmail.com>
*
* github地址: https://github.com/F-loat/mpvue-wxParse
*
* for: Mpvue框架下 微信小程序富文本解析
*/-->
<template>
<!--基础元素-->
<div class="wxParse">
<block v-for="node of wxParseData.nodes" :key="node.index">
<wxParseTemplate :node="node" />
</block>
</div>
</template>
<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';
export default {
name: 'wxParse',
props: {
content: {
type: String,
default() {
return '<div class="color:red;">数据不能为空</div>';
},
},
image: {
type: String,
default() {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
};
},
},
debug: {
type: Boolean,
default() {
return false;
},
},
},
components: {
wxParseTemplate,
},
computed: {
wxParseData() {
const { content, image, debug } = this;
const transData = HtmlToJson(content, image, debug);
if (debug) console.log(JSON.stringify(transData, null, ' '));
return transData;
},
},
};
</script>
<style>
@import url("./wxParse.css");
</style>
<template>
<view class="read-item">
<view class="dot"></view>
<view class="content">
<view class="title">
<text>{{content.question_title}}</text>
</view>
<view class="guide">
<text>{{content.answer_content}}</text>
</view>
<view class="author" v-if="content.author_list && content.author_list.length">
<text>{{content.author_list[0].user_name}}</text>
</view>
</view>
<view class="date">{{content.question_makettime}}</view>
</view>
</template>
<script>
export default {
props: {
item: Object
},
computed: {
content() {
const item = this.item
item.question_makettime = item.question_makettime.substr(5, 5).split('-').join('') + ''
return item
}
}
}
</script>
<style scoped>
.read-item {
width: 100%;
height: 300rpx;
position: relative;
display: flex;
justify-content: space-between;
text-align: left;
}
.date {
width: 160rpx;
text-indent: 1em;
white-space: nowrap;
line-height: 70rpx;
}
.title {
line-height: 80rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 36rpx;
}
.guide {
line-height: 38rpx;
height: 76rpx;
overflow: hidden;
}
.author {
text-align: right;
margin-right: 20rpx;
}
.content {
width: 540rpx;
height: 246rpx;
box-sizing: border-box;
border-radius: 10rpx;
background: linear-gradient(to bottom right, #9653fe, #507fff);
color: #fff;
position: relative;
margin-left: 20rpx;
padding: 2rpx 12rpx 0;
}
.content::before {
content: '';
display: block;
width: 0;
height: 0;
border-width: 15rpx 12rpx;
border-style: solid;
border-color: transparent transparent transparent #6c6dfe;
position: absolute;
top: 20rpx;
right: -20rpx;
}
.dot {
width: 18rpx;
height: 18rpx;
background-color: rgba(108, 109, 254, .6);
position: absolute;
top: 26rpx;
right: 150rpx;
border-radius: 50%;
}
</style>
<template>
<view class="read-item">
<view class="dot"></view>
<view class="date">{{content.hp_makettime}}</view>
<view class="content">
<view class="title">
<text>{{content.hp_title}}</text>
</view>
<view class="guide">
<text>{{content.guide_word}}</text>
</view>
<view class="author" v-if="content.author && content.author.length">
<text>{{content.author[0].user_name}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: Object
},
computed: {
content() {
const item = this.item
item.hp_makettime = item.hp_makettime.substr(5, 5).split('-').join('') + ''
return item
}
}
}
</script>
<style scoped>
.read-item {
width: 100%;
height: 300rpx;
position: relative;
display: flex;
justify-content: space-between;
text-align: left;
}
.date {
width: 160rpx;
text-indent: 1em;
white-space: nowrap;
line-height: 70rpx;
}
.title {
line-height: 80rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 36rpx;
}
.guide {
line-height: 38rpx;
height: 76rpx;
overflow: hidden;
}
.author {
text-align: right;
margin-right: 20rpx;
}
.content {
width: 540rpx;
height: 246rpx;
box-sizing: border-box;
border-radius: 10rpx;
/* background-color: #42adda; */
background: linear-gradient(to bottom right, #9653fe, #507fff);
color: #fff;
position: relative;
margin-right: 20rpx;
padding: 2rpx 12rpx 0;
}
.content::before {
content: '';
display: block;
width: 0;
height: 0;
border-width: 15rpx 12rpx;
border-style: solid;
border-color: transparent #9653fe transparent transparent;
position: absolute;
top: 20rpx;
left: -20rpx;
}
.dot {
width: 18rpx;
height: 18rpx;
background-color: rgba(150, 83, 254, .6);
position: absolute;
top: 26rpx;
left: 150rpx;
border-radius: 50%;
}
</style>
import Vue from 'vue'
import App from './App'
import store from '@/store'
Vue.config.productionTip = false
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
store,
...App
})
app.$mount()
{
"name" : "uni-one",
"appid" : "__UNI__04F77E3",
"description" : "A uni-app project",
"versionName" : "1.0.0",
"versionCode" : "100",
"app-plus" : {/* 5+App特有相关 */
"modules" : {/* 模块配置 */
},
"distribute" : {/* 应用发布信息 */
"android" : {/* android打包配置 */
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {/* ios打包配置 */
},
"sdkConfigs" : {/* SDK配置 */
}
}
},
"quickapp" : {/* 快应用特有相关 */
},
"mp-weixin" : {/* 小程序特有相关 */
"appid" : "wxb7bfcea0160eb9f7"
}
}
{
"pages": [
{
"path": "pages/home/main",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/read/main",
"style": {
"navigationBarTitleText": "文章&问答"
}
},
{
"path": "pages/read/essay/main"
},
{
"path": "pages/read/question/main"
},
{
"path": "pages/movie/main",
"style": {
"navigationBarTitleText": "影评"
}
},
{
"path": "pages/movie/detail/main"
},
{
"path": "pages/daily/main",
"style": {
"navigationBarTitleText": "日报"
}
},
{
"path": "pages/daily/detail/main",
"style": {
"navigationBarTitleText": "日报"
}
}
],
"globalStyle": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "fafafa",
"navigationBarTitleText": "一个",
"navigationBarTextStyle": "black"
},
"tabBar": {
"color": "#130f13",
"selectedColor": "#0f0f0f",
"list": [
{
"pagePath": "pages/home/main",
"text": "ONE",
"iconPath": "static/icon/home.png",
"selectedIconPath": "static/icon/home-active.png"
},
{
"pagePath": "pages/read/main",
"text": "READ",
"iconPath": "static/icon/read.png",
"selectedIconPath": "static/icon/read-active.png"
},
{
"pagePath": "pages/movie/main",
"text": "MOVIE",
"iconPath": "static/icon/movie.png",
"selectedIconPath": "static/icon/movie-active.png"
},
{
"pagePath": "pages/daily/main",
"text": "DAILY",
"iconPath": "static/icon/daily.png",
"selectedIconPath": "static/icon/daily-active.png"
}
]
}
}
\ No newline at end of file
<style scoped>
.cover {
width: 300rpx;
height: 300rpx;
margin: 20rpx auto 0;
border-radius: 16rpx;
box-shadow: 10rpx 10rpx 20rpx rgba(0, 0, 0, .2);
}
.control {
width: 80rpx;
height: 80rpx;
background-color: rgba(0, 0, 0, .4);
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
margin: -60rpx 0 0 -40rpx;
}
.feeds_cover {
width: 100%;
height: 400rpx;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
.control img {
width: 32rpx;
height: 32rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.title {
font-size: 30rpx;
font-weight: bold;
height: 96rpx;
line-height: 48rpx;
margin-top: 40rpx;
text-align: center;
}
</style>
<style>
.meta.div {
height: 120rpx;
padding-left: 40rpx;
position: relative;
}
.meta.div::before {
content: '';
display: block;
position: absolute;
top: 12rpx;
left: 10rpx;
width: 0;
height: 0;
border-width: 12rpx 16rpx;
border-style: solid;
border-color: transparent transparent transparent #000;
animation: circle 1s infinite;
transform-origin: 25% 50%;
}
.meta.div::after {
content: '';
display: block;
position: absolute;
top: 12rpx;
left: 10rpx;
width: 0;
height: 0;
border-width: 12rpx 16rpx;
border-style: solid;
border-color: transparent transparent transparent #000;
animation: fadeIn 1s infinite;
}
.meta.div .avatar {
display: none;
}
.view-more.div {
display: none;
}
@keyframes circle {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(16rpx);
opacity: 0;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
<template>
<div class="article-container">
<div class="title">{{title}}</div>
<wx-parse :content="body"></wx-parse>
</div>
</template>
<script>
import API from '@/utils/api'
import wxParse from '../../../components/mpvue-wxparse/wxParse.vue'
export default {
data() {
return {
loaded: false,
isPlay: false,
audioContext: null,
body: '',
title: ''
}
},
components: {
wxParse
},
onLoad(query) {
const id = query.id
if (!id) console.log('error coured no id find.')
this.getDetail(id)
},
methods: {
async getDetail(id) {
const data = await API.getZhDtl(id)
this.body = data.body
this.title = data.title
}
}
}
</script>
<style scoped>
</style>
<style scoped>
li {
min-height: 160rpx;
display: flex;
align-items: center;
border-bottom: 2rpx solid #fafbff;
padding: 0 20rpx;
}
li:active {
background-color: #f15549;
padding-left: 20rpx;
}
li:active .title, li:active .subtitle {
color: #fff;
}
li img {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
display: block;
}
.desc {
width: 480rpx;
text-align: left;
line-height: 48rpx;
padding-left: 40rpx;
}
.title {
color: #7f7f7f;
font-size: 32rpx;
}
.play {
margin-left: 40rpx;
}
.play img {
width: 40rpx;
height: 40rpx;
}
.slide-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.item-title {
position: absolute;
width: 100%;
box-sizing: border-box;
padding: 0 40rpx 60rpx;
font-size: 36rpx;
text-align: left;
color: #fff;
left: 0;
bottom: 0;
z-index: 11;
}
swiper {
width: 100%;
height: 400rpx;
position: fixed;
top: 0;
left: 0;
}
swiper-item {
position: relative;
}
.layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, .3));
}
.list {
margin-top: 400rpx;
}
</style>
<template>
<div class="container">
<swiper :indicator-dots="true" :autoplay="true" :circular="true">
<block v-for="v in top_stories" :key="v.id">
<swiper-item @tap="toDtl(v.id)">
<image :src="v.image" class="slide-image" mode="center"/>
<div class="item-title">{{v.title}}</div>
<div class="layer"></div>
</swiper-item>
</block>
</swiper>
<ul class="list">
<li v-for="v in all_stories" :key="v.id" @tap="toDtl(v.id)">
<img :src="v.image" alt="cover">
<div class="desc">
<div class="title">
{{v.title}}
</div>
</div>
<div class="play">
<img src="/static/assert/arrow-right.png" alt="play">
</div>
</li>
</ul>
</div>
</template>
<script>
import API from '@/utils/api'
export default {
data() {
return {
top_stories: [],
stories: [],
innerAudioContext: ''
}
},
mounted() {
this.getDailyList()
},
computed: {
all_stories() {
return this.stories.map(v => ({
...v,
image: v.images[0]
}))
}
},
methods: {
async getDailyList() {
const res = await API.getZhList()
console.log(res.top_stories)
this.top_stories = res.top_stories
this.stories = res.stories
},
toDtl(id) {
wx.navigateTo({ url: '/pages/daily/detail/main?id=' + id })
}
}
}
</script>
<template>
<div class="container">
<image class="cover" :src="data.hp_img_url" mode="widthFix" />
<view class="cover-author">
<text class="gray">{{data.hp_author}}</text>
</view>
<view class="content">
<text>{{content}}</text>
</view>
<view class="content-author">
<text class="gray">{{data.text_authors}}</text>
</view>
<weather :weather="weather" v-if="weather.status === 'ok'"></weather>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import weather from './weather'
export default {
mounted() {
this.initPage()
},
components: {
weather
},
computed: {
...mapState('home', ['data']),
...mapState('weather', ['weather']),
content() {
return this.data.hp_content.split('by')[0]
}
},
methods: {
...mapActions('home', ['getNewIds', 'getHomeData']),
async initPage() {
await this.getNewIds()
await this.getHomeData()
}
}
}
</script>
<style scoped>
.cover {
width: 100%;
}
.cover-author {
width: 100%;
height: 100rpx;
line-height: 100rpx;
margin-bottom: 30rpx;
}
.content {
width: 80%;
margin: 0 auto;
line-height: 58rpx;
text-align: left;
}
.content-author {
height: 100rpx;
line-height: 100rpx;
font-size: 20rpx;
}
</style>
<template>
<div class="weather">
<div class="date">{{day}}</div>
<div class="location">
{{weather.basic.location}}
</div>
<img :src="'https://petrify.oss-cn-beijing.aliyuncs.com/weather/' + weather.now.cond_code + '.png'" alt="">
<div class="cond-text">{{weather.now.cond_txt}}</div>
<div class="tmp"><span>{{weather.now.tmp}}°C</span></div>
<div class="fl">体感:<span>{{weather.now.fl}}°C</span></div>
</div>
</template>
<script>
const DAY_LIST = ['Sun', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']
export default {
props: {
weather: Object
},
computed: {
day() {
const day = new Date().getDay()
return DAY_LIST[day]
}
}
}
</script>
<style scoped>
.weather {
height: 170rpx;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
font-size: 36rpx;
justify-content: space-around;
}
.date {
color: #ecc88e;
font-size: 48rpx;
font-weight: 700;
padding: 0 20rpx;
}
.location {
color: #b4b0ad;
}
img {
width: 80rpx;
height: 80rpx;
}
.tmp span, .fl span {
color: #52b9b6;
}
</style>
<template>
<block>
<v-article
:title="currentMovie.title"
:user_name="currentMovie.user ? currentMovie.user.user_name : ''"
:content="currentMovie.content || ''"
:summary="currentMovie.summary || ''"
></v-article>
</block>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import article from '@/components/article'
export default {
onLoad(query) {
this.clearMovieDetail()
const { id } = query
this.initPage(id)
},
components: {
'v-article': article
},
computed: {
...mapState('movie', ['currentMovie'])
},
methods: {
...mapActions('movie', ['getMovieDetail', 'clearMovieDetail']),
async initPage(id) {
await this.getMovieDetail(id)
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="container">
<navigator
v-for="v in movies"
:key="v.item_id"
:url="'/pages/movie/detail/main?id=' + v.item_id"
class="item"
>
<movie-detail :movie="v"></movie-detail>
</navigator>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import movieDetail from '@/components/movieItem'
export default {
mounted () {
this.initPage()
},
components: {
movieDetail
},
computed: {
...mapState('movie', ['movies'])
},
methods: {
...mapActions('movie', ['getMovieList']),
async initPage() {
await this.getMovieList()
}
}
}
</script>
<style scoped>
navigator {
width: 100%;
}
.item {
width: 100%;
height: 170rpx;
}
.item:nth-child(odd) {
background-color: #e5e4df;
}
.item:nth-child(even) {
background-color: #eae9e4;
}
</style>
<template>
<block>
<v-article
:title="readContent.essay.hp_title"
:user_name="readContent.essay.hp_author"
:content="readContent.essay.hp_content || ''"
></v-article>
</block>
</template>
<script>
import article from '@/components/article'
import { mapState, mapActions } from 'vuex'
export default {
onLoad(params) {
this.clearReadContent({type: 'essay'})
const { id } = params
this.getReadContent({ type: 'essay', id })
},
components: {
'v-article': article
},
computed: {
...mapState('read', ['readContent'])
},
methods: {
...mapActions('read', ['getReadContent', 'clearReadContent'])
}
}
</script>
<style scoped>
</style>
<template>
<div class="container">
<view class="mode-title" v-if="readList.essay && readList.essay.length">
<view class="mode-title-word">
<text>阅读</text>
</view>
</view>
<navigator v-for="v in readList.essay" :key="v.content_id" :url="'/pages/read/essay/main?id=' + v.content_id">
<read-list :item="v"></read-list>
</navigator>
<view class="mode-title" v-if="readList.question && readList.question.length">
<view class="mode-title-word">
<text>问答</text>
</view>
</view>
<navigator v-for="v in readList.question" :key="v.question_id" :url="'/pages/read/question/main?id=' + v.question_id">
<question-list :item="v"></question-list>
</navigator>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import readList from '@/components/readList'
import questionList from '@/components/questionList'
export default {
mounted() {
this.getReadList()
},
components: {
readList,
questionList
},
computed: {
...mapState('read', ['readList'])
},
methods: {
...mapActions('read', ['getReadList'])
}
}
</script>
<style scoped>
.mode-title {
height: 80rpx;
line-height: 80rpx;
position: relative;
margin-bottom: 20rpx;
}
.mode-title .mode-title-word {
width: 120rpx;
margin: 0 auto;
font-size: 36rpx;
background-color: #fff;
}
.mode-title:before {
content: '';
display: block;
width: 80%;
height: 2rpx;
background-color: #b4b4b5;
position: absolute;
top: 50%;
left: 10%;
z-index: -1;
}
</style>
<template>
<div class="wrapper">
<view class="title">
<text>{{detail.question_title}}</text>
</view>
<view class="ask">
<view class="asker" v-if="detail.answerer">
<text>{{detail.asker.user_name}}问:</text>
</view>
<view class="asker" v-else>
<text>网友问:</text>
</view>
<wx-parse :content="detail.question_content || ''"></wx-parse>
</view>
<view class="divider"></view>
<view class="answer">
<view class="answerer" v-if="detail.answerer">
<text>{{detail.answerer.user_name}}答:</text>
</view>
<view class="answerer" v-else>
<text>网友答:</text>
</view>
<wx-parse :content="detail.answer_content || ''"></wx-parse>
</view>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import wxParse from '../../../components/mpvue-wxparse/wxParse.vue'
export default {
onLoad(params) {
this.clearReadContent({type: 'question'})
const { id } = params
this.getReadContent({ type: 'question', id })
},
components: {
wxParse
},
computed: {
...mapState('read', ['readContent']),
detail() {
return this.readContent.question
}
},
methods: {
...mapActions('read', ['getReadContent', 'clearReadContent'])
}
}
</script>
<style scoped>
.title {
font-size: 32rpx;
overflow: hidden;
text-align: center;
padding: .8em;
font-weight: bold;
}
.asker, .answerer {
font-size: 30rpx;
padding-left: 1em;
height: 60rpx;
}
.divider {
width: 90%;
margin: 15rpx auto;
position: relative;
height: 2rpx;
background-color: #b4b4b4;
}
.divider::before {
content: '';
width: 50rpx;
height: 2rpx;
background-color: #fff;
position: absolute;
top: 0;
left: calc(50% - 25rpx);
}
.divider::after {
content: '';
display: block;
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #b4b4b4;
position: absolute;
top: -4rpx;
left: calc(50% - 5rpx);
}
</style>
import Vue from 'vue'
import Vuex from 'vuex'
import home from './modules/home'
import movie from './modules/movie'
import read from './modules/read'
import weather from './modules/weather'
// import music from './modules/music'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
home: {
namespaced: true,
...home
},
movie: {
namespaced: true,
...movie
},
read: {
namespaced: true,
...read
},
weather: {
namespaced: true,
...weather
}
}
})
export default store
import { CHANGE_HOME_DATA, STORE_ID_LIST } from './../mutations_type'
import API from '@/utils/api'
const state = {
ids: [],
data: {
hp_content: '',
hp_img_url: '',
hp_author: '',
text_authors: ''
}
}
const mutations = {
[CHANGE_HOME_DATA](state, payload) {
state.data = payload.data
},
[STORE_ID_LIST](state, payload) {
state.ids = payload.ids
}
}
const actions = {
async getNewIds({ commit }) {
const { data } = await API.getNewIds()
commit(STORE_ID_LIST, { ids: data })
},
async getHomeData({ commit, state }) {
const { data } = await API.getHomeData(state.ids[0])
commit(CHANGE_HOME_DATA, { data })
}
}
export default {
state,
mutations,
actions
}
import { CHANGE_MOVIE_LIST, CHANGE_CURRENT_MOVIE } from './../mutations_type'
import API from '@/utils/api'
const state = {
movies: [],
currentMovie: {}
}
const mutations = {
[CHANGE_MOVIE_LIST](state, payload) {
state.movies = payload.movies
},
[CHANGE_CURRENT_MOVIE](state, payload) {
state.currentMovie = payload.data
}
}
const actions = {
async getMovieList({ commit }) {
const { data } = await API.getMovieList()
commit(CHANGE_MOVIE_LIST, { movies: data })
},
async getMovieDetail({ commit, state }, id) {
const { data: { data } } = await API.getMovieDetail(id)
commit(CHANGE_CURRENT_MOVIE, { data: data[0] })
},
async getMovieArticleDetail({ commit, state }, id) {
const { data: { data } } = await API.getMovieArticleDetail(id)
commit(CHANGE_CURRENT_MOVIE, { data: data[0] })
},
clearMovieDetail({ commit }) {
commit(CHANGE_CURRENT_MOVIE, { data: {} })
}
}
export default {
state,
mutations,
actions
}
import API from '@/utils/api'
import { CHANGE_CURRENT_READ, CHANGE_READ_LIST } from './../mutations_type'
const state = {
readList: {
essay: [],
question: [],
serial: []
},
readContent: {
essay: {},
question: {}
}
}
const mutations = {
[CHANGE_READ_LIST] (state, payload) {
state.readList = payload.data
},
[CHANGE_CURRENT_READ] (state, payload) {
state.readContent[payload.type] = payload.data
}
}
const actions = {
async getReadList({ commit, state }) {
const { data } = await API.getReadList()
commit(CHANGE_READ_LIST, { data })
},
async getReadContent({ commit, state }, { type, id }) {
const { data } = await API.getReadDetail(type, id)
commit(CHANGE_CURRENT_READ, { type, data })
},
async clearReadContent({ commit, state }, { type }) {
commit(CHANGE_CURRENT_READ, { type, data: {} })
}
// async getReadComment({ commit, state }, id) {
// // const { data } = await API.getReadComment(id)
// // commit(CHANGE_CURRENT_READ, { data })
// }
}
export default {
state,
mutations,
actions
}
import API from '@/utils/api'
import { SET_LOCATION, SET_WEATHER } from '../mutations_type'
const state = {
location: {
latitude: '',
longitude: ''
},
weather: {
basic: {},
now: {},
update: {},
status: ''
}
}
const mutations = {
[SET_LOCATION] (state, payload) {
state.location = payload.location
},
[SET_WEATHER] (state, payload) {
state.weather = payload.weather
}
}
const actions = {
async getWeather({ state, commit }) {
console.log('getWeather')
const location = state.location
const data = await API.getWeather(`${location.latitude},${location.longitude}`)
commit(SET_WEATHER, { weather: data.result })
}
}
export default {
state,
mutations,
actions
}
export const CHANGE_HOME_DATA = 'CHANGE_HOME_DATA'
export const STORE_ID_LIST = 'STORE_ID_LIST'
export const CHANGE_MOVIE_LIST = 'CHANGE_MOVIE_LIST'
export const CHANGE_CURRENT_MOVIE = 'CHANGE_CURRENT_MOVIE'
export const CHANGE_READ_LIST = 'CHANGE_READ_LIST'
export const CHANGE_CURRENT_READ = 'CHANGE_CURRENT_READ'
export const CHANGE_MUSIC_LIST = 'CHANGE_MUSIC_LIST'
export const CHANGE_CURRENT_MUSIC = 'CHANGE_CURRENT_MUSIC'
export const SET_LOCATION = 'SET_LOCATION'
export const SET_WEATHER = 'SET_WEATHER'
import request from './request'
const baseURL = `https://petrify.cc`
// const baseURL = 'http://192.168.29.238:7001'
request.config.baseURL = baseURL
const dailyRequest = (id) => request.post('/v1/daily', {
url: `/api/4/news/${id}`
})
const api = {
// picture
getNewIds: () => request.get(`/v1/one?${encodeURI('url=/api/hp/idlist/0?version=3.5.0&platform=android')}`),
getHomeData: (id) => request.get(`/v1/one?${encodeURI('url=/api/hp/detail/' + id + '?version=3.5.0&platform=android')}`),
// read
getReadList: () => request.get(`/v1/one?${encodeURI('url=/api/reading/index/?version=3.5.0&platform=android')}`),
getReadDetail: (type, id) => request.get(`/v1/one?${encodeURI('url=/api/' + type + '/' + id + '?version=3.5.0&platform=android')}`),
getReadComment: (id) => request.get(`/v1/one?${encodeURI('url=/api/comment/praiseandtime/essay/' + id + '/0?version=3.5.0&platform=android')}`),
getMovieList: () => request.post('/v1/two', {
url: '/api/channel/movie/more/0?channel=wdj&version=4.0.2&uuid=ffffffff-a90e-706a-63f7-ccf973aae5ee&platform=android'
}),
getMovieDetail: (id) => request.get(`/v1/one?${encodeURI('url=/api/movie/' + id + '/story/1/0?version=3.5.0&platform=android')}`),
getWeather: (location) => request.get(`/v1/weather?location=${location}`),
// 知乎日报
getZhList: () => dailyRequest('latest'),
getZhDtl: (id) => dailyRequest(id)
}
export default api
import Fly from 'flyio/dist/npm/wx'
const request = new Fly()
const errorPrompt = (err) => {
wx.showToast({
title: err.message || 'fetch data error.',
icon: 'none'
})
}
request.interceptors.request.use((request) => {
wx.showNavigationBarLoading()
return request
})
request.interceptors.response.use((response, promise) => {
wx.hideNavigationBarLoading()
// if (!(response && response.data && response.data.res === 0)) {
// errorPrompt(response)
// }
return promise.resolve(response.data)
}, (err, promise) => {
wx.hideNavigationBarLoading()
errorPrompt(err)
return promise.reject(err)
})
export default request
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册