新闻推荐前端代码

This commit is contained in:
RuyiLuo
2021-12-05 14:41:06 +08:00
parent 185dd76c40
commit 75589f887b
34 changed files with 24805 additions and 2 deletions

14
.gitignore vendored
View File

@@ -1,2 +1,12 @@
codes/news_rec_web/Vue-newsinfo/node_modules
./__pycache__
/codes/news_recsys/news_rec_web/Vue-newsinfo/node_modules
/codes/news_recsys/news_rec_server/conf/__pycache__
/codes/news_recsys/news_rec_server/controller/__pycache__
/codes/news_recsys/news_rec_server/dao/__pycache__
/codes/news_recsys/news_rec_server/dao/entity/__pycache__
/codes/news_recsys/news_rec_server/logs
/codes/news_recsys/news_rec_server/materials/material_process/__pycache__
/codes/news_recsys/news_rec_server/materials/news_scrapy/sinanews/__pycache__
/codes/news_recsys/news_rec_server/materials/news_scrapy/sinanews/spiders/__pycache__
/codes/news_recsys/news_rec_server/materials/user_process/__pycache__
/codes/news_recsys/news_rec_server/recprocess/__pycache__
/codes/news_recsys/news_rec_server/recprocess/recall/__pycache__

View File

@@ -0,0 +1,19 @@
{
"presets": [
"env",
"stage-0"
],
"plugins": [
"transform-runtime",
"transform-remove-strict-mode",
[
"component",
[
{
"libraryName": "mint-ui",
"style": true
}
]
]
]
}

View File

@@ -0,0 +1,68 @@
## 基于vue2.0的商城资讯
***
- 这个项目是跟着网上的视频一步一步做的对于初学vue的同学来说挺合适的基本上vue入门的技术都涵盖了可以全面的了解整个项目是怎么运作的各个组件间的传值和交互路由还有vuex的相关知识,因为是自己学习的项目里面写了大量的注释可供参考。
- 项目学习到的知识点
+ 基于vue的框架mui Mint-ui的基本使用。
+ 基于nodejs的npm包管理工具、打包工具webpack和与之相对应的插件以及babel的配置。
+ vue路由的相关知识路由的配置和渲染以及编程式路由的使用。
+ vue-axios的使用,项目里调用接口都是用的这个异步ajax插件。
+ 全局组件、过滤器的使用。
+ watch和计算属性的使用。
+ vuex的使用--购物车里商品信息的同步都是基于vuex来实现的。
## 运行
> 1. 本地安装node环境,下载项目,在项目根目录命令行输入命令`npm install`安装依赖包
> 2. 运行`npm run dev`启动项目
> 3. 访问地址`http://localhost:3000`
## 项目截图
![image](https://s2.ax1x.com/2019/08/24/msoWNT.png)
![image](https://s2.ax1x.com/2019/08/24/msTTJS.png)
![image](https://s2.ax1x.com/2019/08/24/msT5If.png)
![image](https://s2.ax1x.com/2019/08/24/msTqMj.png)
![image](https://s2.ax1x.com/2019/08/24/msToi8.png)
![image](https://s2.ax1x.com/2019/08/24/msT7Rg.png)
![image](https://s2.ax1x.com/2019/08/24/msTLss.png)
![image](https://s2.ax1x.com/2019/08/24/msTOLn.png)
![image](https://s2.ax1x.com/2019/08/24/msTjZq.png)
![image](https://s2.ax1x.com/2019/08/24/msTvd0.png)
## PS
感谢黑马老师提供的接口`http://www.liulongbin.top:3005`确实讲的挺好目前还一直提供使用大家需要这个视频的话可以去bilibili搜索vue教程-黑马。
"d11c2736-0a1d-46e8-8c22-e12909723f81"
/recsys/news_detail
http://10.170.1.181:3000/recsys/news_detail?news_id=d11c2736-0a1d-46e8-8c22-e12909723f81
http://10.170.1.181:8686/#/NewsLists
## 注册时候的信息
1. user_name
2. pass_wd
3. nick_name
4. age
5. gender
6. city
http://10.170.1.181:3000/recsys/register
https://github.com/JerryYuanJ/a-vue-app-template
http://elemefe.github.io/mint-ui/#/button

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
{
"name": "0807_H5",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"dependencies": {
"@vant/area-data": "^1.1.3",
"axios": "^0.19.0",
"bootstrap": "^3.4.1",
"into": "^0.2.0",
"js-pinyin": "^0.1.9",
"less-loader": "^10.2.0",
"mint-ui": "^2.2.13",
"moment": "^2.24.0",
"vant": "^2.12.34",
"vue": "^2.6.10",
"vue-addr-picker": "^1.0.8",
"vue-axios": "^2.1.4",
"vue-preview": "^1.1.3",
"vue-router": "^3.0.7",
"webpack": "^4.39.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-component": "^1.1.1",
"babel-plugin-transform-remove-strict-mode": "0.0.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^3.1.0",
"file-loader": "^4.1.0",
"html-webpack-plugin": "^3.2.0",
"jquery": "^3.4.1",
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^2.1.0",
"vue-loader": "^15.7.1",
"vue-template-compiler": "^2.6.10",
"vuex": "^2.5.0",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack-parallel-uglify-plugin": "^2.0.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open --port 8686 --contentBase src --hot --host 0.0.0.0",
"start": "nodemon src/main.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,140 @@
<template>
<div class="app-container">
<!-- <router-view></router-view> -->
<keep-alive>
<router-view v-if='$route.meta.keepAlive' />
</keep-alive>
<router-view v-if='!$route.meta.keepAlive' />
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
},
computed: {
}
}
</script>
<style>
* {
padding: 0;
margin: 0;
border: 0;
outline: 0;
box-sizing: border-box;
}
body,
html {
width: 100%;
height: 100%;
/* overflow: hidden; */
}
/* 去掉获取焦点时的边框 */
input {
background: none;
border: none;
outline: none;
display: black;
}
/* 登录注册页面输入框 */
input[type='text'],
input[type='password'] {
background-color: transparent !important;
padding: 0 !important;
margin: 0 !important;
border: 0 !important;
font-size: 1.2rem;
color: white !important;
height: 1.5rem !important;
}
</style>
<style scoped>
/* input框 */
/deep/ .van-cell__value {
color: white;
width: 100%;
padding: .7rem 1rem .3rem 1rem;
outline: none;
border-radius: 1.5rem;
background-color: rgba(255, 255, 255, 0.25);
letter-spacing: 1px;
min-height: 2rem;
margin-top: 1.5rem;
}
/deep/ .van-cell__value:hover,
/deep/.van-cell__value:focus {
color: white;
border: 1px solid rgba(255, 255, 255, 0.5);
background-color: transparent;
}
/deep/ .login-container [data-v-7ba5bd90] .van-cell__value {
height: 2rem;
}
/* radio */
/deep/ .van-radio-group--horizontal {
justify-content: space-around
}
/* radio的label */
/deep/ .van-radio__label {
color: rgba(255, 255, 255, 0.25);
font-size: .9rem;
}
/* 复选框label的颜色 */
/deep/ .van-checkbox__label {
color: white;
font-size: .9rem;
}
/* 新闻列表上下左右留白 */
/deep/ [data-v-7c729b82] .van-cell__value {
margin-top: 1rem;
padding: 0px 20px;
height: 6rem;
}
/* tab高度 */
/deep/ .van-tabs--line .van-tabs__wrap {}
/* tab选中的颜色 */
/deep/ .van-tabs__line {
background-color: #1989FA;
}
/* tab字体 */
/deep/.van-tab__text--ellipsis {
font-size: 18px;
font-weight: 800;
color: cornflowerblue;
}
/* navBar标题 */
/deep/ .van-nav-bar__title {
max-width: 60%;
margin: 0 auto;
color: #323233;
font-weight: 600;
font-size: 20px;
}
/* 个人中心退出登录按钮 */
/deep/ span[data-v-4aa99128] {
font-size: 1rem;
}
</style>

View File

@@ -0,0 +1,2 @@
@nav-bar-background-color: @blue;

View File

@@ -0,0 +1,182 @@
/* container */
.login-container {
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.25;
letter-spacing: 1px;
display: block;
position: relative;
z-index: 0;
padding: 3rem 4rem 0 4rem;
width: 100vw;
height: 100vh;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/283591/login-background.jpg) no-repeat;
background-size: 100% 100%;
}
/* 紫色的遮罩 */
.login-container:after {
content: '';
display: inline-block;
position: absolute;
z-index: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image: radial-gradient(ellipse at left bottom, rgba(22, 24, 47, 1) 0%, rgba(38, 20, 72, .9) 59%, rgba(17, 27, 75, .9) 100%);
box-shadow: 0 -20px 150px -20px rgba(0, 0, 0, 0.5);
}
.form-login {
position: relative;
z-index: 1;
padding-bottom: 4.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}
/* 登录和注册的切换 */
.login-nav {
position: relative;
padding: 0;
}
.login-nav__item {
list-style: none;
display: inline-block;
}
.login-nav__item+.login-nav__item {
margin-left: 2.25rem;
}
.login-nav__item a {
position: relative;
color: rgba(255, 255, 255, 0.5);
text-decoration: none;
text-transform: uppercase;
font-weight: 500;
font-size: 1.25rem;
padding-bottom: .5rem;
transition: .20s all ease;
}
.login-nav__item.active a,
.login-nav__item a:hover {
color: #ffffff;
transition: .15s all ease;
}
.login-nav__item a:after {
content: '';
display: inline-block;
height: 10px;
background-color: rgb(255, 255, 255);
position: absolute;
right: 100%;
bottom: -1px;
left: 0;
border-radius: 50%;
transition: .15s all ease;
}
.login-nav__item a:hover:after,
.login-nav__item.active a:after {
background-color: rgb(17, 97, 237);
height: 2px;
right: 0;
bottom: 2px;
border-radius: 0;
transition: .20s all ease;
}
.login__label {
display: block;
padding-left: 1rem;
}
.login__label,
.login__label--checkbox {
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
font-size: .75rem;
margin-bottom: 1rem;
}
.login__label--checkbox {
display: inline-block;
position: relative;
padding-left: 1.5rem;
margin-top: 2rem;
margin-left: 1rem;
color: #ffffff;
font-size: .75rem;
text-transform: inherit;
}
.login__input {
color: white;
/* font-size: 1.15rem; */
width: 100%;
/* padding: .5rem 1rem; */
/* border: 2px solid transparent; */
outline: none;
border-radius: 1.5rem;
background-color: rgba(255, 255, 255, 0.25);
letter-spacing: 1px;
min-height: 1rem;
}
.login__input:hover,
.login__input:focus {
color: white;
border: 2px solid rgba(255, 255, 255, 0.5);
background-color: transparent;
}
.login__input+.login__label {
margin-top: 1.5rem;
}
.login__input--checkbox {
position: absolute;
top: .1rem;
left: 0;
margin: 0;
}
.login__submit {
color: #ffffff;
font-size: 1rem;
font-family: 'Montserrat', sans-serif;
text-transform: uppercase;
letter-spacing: 1px;
margin-top: 1rem;
padding: .75rem;
border-radius: 2rem;
display: block;
width: 100%;
background-color: rgba(17, 97, 237, .75);
border: none;
cursor: pointer;
}
.login__submit:hover {
background-color: rgba(17, 97, 237, 1);
}
.login__forgot {
display: block;
margin-top: 3rem;
text-align: center;
color: rgba(255, 255, 255, 0.75);
font-size: .75rem;
text-decoration: none;
position: relative;
z-index: 1;
}
.login__forgot:hover {
color: rgb(17, 97, 237);
}

View File

@@ -0,0 +1,46 @@
// 保存cookie
// json 需要存储cookie的对象
// days 默认存储多少天
function setCookie(json, days) {
// 设置过期时间
let data = new Date(
new Date().getTime() + days * 24 * 60 * 60 * 1000
).toUTCString();
for (var key in json) {
document.cookie = key + "=" + json[key] + "; expires=" + data
}
console.log(document.cookie);
}
// 获取cookie
// name 需要获取cookie的key
function getCookie(name) {
var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
if (arr != null) {
return unescape(arr[2])
} else {
return null
}
}
// 删除cookie
// name 需要删除cookie的key
function clearCookie(name) {
let json = {};
json[name] = '';
setCookie(json, -1)
}
export default {
setCookie,
getCookie,
clearCookie
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,170 @@
<template>
<div class='login-container'>
<mt-header fixed :title="val">
<mt-button @click="changeToLogin" icon="back" slot="left" v-show="!isLogin">返回</mt-button>
</mt-header>
<div class="info">
<mt-field label="用户名" placeholder="Input username" v-model="model.username"></mt-field>
<mt-field label="密码" placeholder="Input password" type="password" v-model="model.passwd"></mt-field>
<div v-show='!isLogin'>
<!-- <input type="text" id="name" name="name" required minlength="4" maxlength="8" size="10" class="myInput"> -->
<mt-field label="验证密码" placeholder="Input password" type="password"></mt-field>
<mt-field label="年龄" placeholder="Input age" v-model="model.age"></mt-field>
<mt-field label="性别" placeholder="male/female" v-model="model.gender"></mt-field>
<mt-field label="城市" placeholder="city" v-model="model.city"></mt-field>
<!--
<div>
<city-picker ref="citypicker" @confirm="getCity"></city-picker>
<span>选择城市</span><button @click="open('citypicker')">选择城市</button><span>{{model.city}}</span>
</div> -->
<!--
<span>性别</span>
<div @click="sexVisible = true">{{model.gender}}</div>
<div>
<mt-popup v-model="sexVisible" position="bottom">
<mt-picker :slots="slots" @change="onValuesChange"></mt-picker>
</mt-popup>
</div> -->
</div>
</div>
<!-- <div class='change'> -->
<!-- <button @click="changeToLogin">登录</button> -->
<!-- <button @click="changeToRegister">注册</button> -->
<!-- </div> -->
<div class="ensure">
<mt-button type="primary" size='large' @click="login">确认{{this.val}}</mt-button>
</div>
<div class='center'>
<div v-if='isLogin'>
未创建帐号立即<span @click="changeToRegister">注册</span>
</div>
<div v-else>
已有帐号立即<span @click="changeToLogin">登录</span>
</div>
</div>
</div>
</template>
<script>
import { DatetimePicker,Toast,Popup,Picker } from 'mint-ui';
export default {
data(){
return{
model:{
username: '',
passwd: '',
city: '',
age: '',
gender: ''
},
val: '登录',
isLogin: true,
sexVisible: false, //选择器的显示与影藏
slots: [
{
flex: 1,
values: ['male','female'],
className: 'slot1',
textAlign: 'center',
flex: 1
}
],
city: []
// sex: '男'
}
},
methods:{
login(){
let url = '/recsys/'
let state = this.val === '登录' ? 'login' : 'register'
url += state
console.log(url)
let res = this.val !== '登录' ? this.model : {username: this.model.username, passwd: this.model.passwd}
this.axios.post(url, res).then(resource => {
if (resource.status === 200) {
// this.news_content = resource.data.data
// console.log(this.news_content)
localStorage.username = res.username
console.log(resource)
this.$router.push('/NewsLists')
} else {
Toast('加载数据失败')
}
})
},
open(picker) {
this.$refs[picker].open();
},
getCity(city) {
//处理选择的城市
this.model.city = city.join('-')
console.log(this.model) //得到选择的城市数据
},
changeToLogin(){
this.val = '登录',
this.isLogin = true
},
changeToRegister(){
this.val = '注册'
this.isLogin = false
},
onValuesChange(picker, values) {
//console.log(values)
this.model.gender = values[0];
this.sexVisible = false;
console.log(this.model.gender)
},
},
}
</script>
<style scoped>
/* .login-container{
margin-top: 100px;
} */
.login-card{
width: 25rem;
margin: 6rem auto;
}
.checkbox{
margin-bottom: 12px;
}
.ensure{
margin: 2% 20% 0.3% 20%;
}
.center{
text-align: center;
margin-top: 1rem;
}
.center span{
color: #409EFF;
}
.myInput{
display: inline-block;
width: 60%;
margin: 0 20% 0 20%;
}
.info{
margin: 10px 4% 0 4%;
}
</style>

View File

@@ -0,0 +1,120 @@
<template>
<div class="my-info">
<van-nav-bar title="个人中心" size="normal" />
<div class="my-icon">
<div class="icon-name">
<img src="../images/datawhale.png" alt="头像">
<div class="username">{{username}}</div>
</div>
<van-button class="quitBto" size="small" plain round type="info" @click="quit">退出登录</van-button>
</div>
<!-- <div class="setting">设置</div> -->
<div class="about">
DataWhale 新闻推荐开源项目
</div>
<div class="datawhale">
Datawhale是一个专注于数据科学与AI领域的开源组织汇集了众多领域院校和知名企业的优秀学习者
聚合了一群有开源精神和探索精神的团队成员Datawhale for the learner和学习者一起成长为愿景
鼓励真实地展现自我开放包容互信互助敢于试错和勇于担当同时 Datawhale 用开源的理念去探
索开源内容开源学习和开源方案赋能人才培养助力人才成长建立起人与人人与知识人与企业和
人与未来的联结
</div>
<img src="../images/dw.png" alt="二维码" class="dwimg">
<bottomBarVue></bottomBarVue>
</div>
</template>
<style scoped>
.content {
margin-top: 40px;
}
.mint-cell {
min-height: 40px;
}
span {
font-size: 13px;
}
</style>
<script>
import bottomBarVue from "./bottomBar.vue"
export default {
data() {
return {
username: 'user'
}
},
components: {
bottomBarVue
},
methods: {
quit() {
/*删除cookie*/
this.cookie.clearCookie('LoginName')
this.cookie.clearCookie('openId')
this.$router.push('/signIn')
}
},
created() {
// this.username = localStorage.username
this,
this.username = this.cookie.getCookie('LoginName')
}
}
</script>
<style scoped>
.my-icon {
height: 12rem;
background-color: #1a91e9;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-evenly;
align-content: center
}
.icon-name {
display: flex;
justify-content: center;
align-items: center;
}
.icon-name img {
display: block;
width: 4.5rem;
height: 4.5rem;
border-radius: 3rem;
}
.username {
margin-left: 10px;
color: white;
font-size: 1.5rem;
}
.about {
/* display: flex;
justify-content: space-between; */
padding-top: 20px;
padding-bottom: 20px;
font-size: 1.5rem;
text-align: center;
font-weight: bold;
}
.datawhale {
font-size: 1.2rem;
padding: 0 20px 20px 20px;
text-indent: 2em;
line-height: 2.4rem;
}
.dwimg {
width: 150px;
height: 150px;
display: block;
margin: 15px auto;
}
</style>

View File

@@ -0,0 +1,235 @@
<template>
<div>
<van-nav-bar left-text="返回" left-arrow @click-left="onClickLeft" :fixed='isFixed' />
<div class="newsinfo-continer">
<div class="newsTitle">
<!--大标题-->
<h1>{{ news_content.title }}</h1>
<!--子标题-->
<p>
<span>发布时间{{ news_content.ctime}}</span>
<!-- <span>点击次数{{ news_content.click}} </span> -->
<!-- <span>喜欢{{ likeNum }} </span>
<span>收藏{{ collectNum }} </span> -->
<span>标签{{cate}}</span>
</p>
<hr>
</div>
<!--内容区域-->
<div class="content" v-html="content"></div>
<div class="editor" v-html="editor"></div>
<!--如果使用接口的话使用这个id(就是路由的id值)穿给子组件用来根据这个值加载对应的评论,没接口就算了-->
<!-- <Comment :id="this.id"></Comment> -->
<div id="action">
<span>喜欢:
<svg class="icon" aria-hidden="true" v-show="!islike" @click="iflike">
<use xlink:href="#icon-xihuan1"></use>
</svg>
<svg class="icon" aria-hidden="true" v-show="islike" @click="iflike">
<use xlink:href="#icon-xihuan"></use>
</svg>
</span>
<span>收藏:
<svg class="icon" aria-hidden="true" v-show="!iscollection" @click="ifcollection">
<use xlink:href="#icon-shoucang"></use>
</svg>
<svg class="icon" aria-hidden="true" v-show="iscollection" @click="ifcollection">
<use xlink:href="#icon-shoucang1"></use>
</svg>
</span>
</div>
</div>
<!-- <bottomBarVue></bottomBarVue> -->
<div class="blank"></div>
</div>
</template>
<script>
import bottomBarVue from './bottomBar.vue'
// 导入定义的评论组件,哪里用哪里导
// import Comment from '../subcomments/comment.vue'
import {
Toast
} from 'mint-ui'
export default {
data() {
return {
// 获取路由地址的id,根据这个id来展示不同的数据。
id: this.$route.params.id,
news_content: [],
content: '',
editor: '',
islike: false,
iscollection: false,
isFixed: true,
likeNum: this.$route.params.likes,
collectNum: this.$route.params.collections,
cate: this.$route.params.cate
}
},
methods: {
onClickLeft() {
this.$router.go(-1);
},
getNewsInfo() {
let reg = /责任编辑/;
let user_name = localStorage.username;
this.axios.get("/recsys/news_detail?news_id=" + this.id + '&user_name=' + user_name).then(resource => {
if (resource.status === 200) {
this.news_content = resource.data.data
this.content = this.news_content.content.split(reg)[0]
this.editor = '责任编辑:' + this.news_content.content.split(reg)[1]
if (resource.data.data.likes == true) {
this.islike = true
} else {
this.islike = false
}
if (resource.data.data.collections == true) {
this.iscollection = true
} else {
this.iscollection = false
}
} else {
Toast('加载数据失败')
}
})
},
sendInfo() {
var val = {
user_name: localStorage.username,
news_id: this.id,
action_time: Date.now(),
action_type: 'read',
}
console.log(val)
this.axios.post("/recsys/action", val).then(resource => {
if (resource.status === 200) {} else {
Toast('加载数据失败')
}
})
},
iflike() {
this.islike = !this.islike
var val = {
user_name: localStorage.username,
news_id: this.id,
action_time: Date.now(),
action_type: `likes:${this.islike}`,
}
this.axios.post("/recsys/action", val).then(resource => {
if (resource.status === 200) {
// this.news_content = resource.data.data
// console.log(this.news_content)
} else {
Toast('加载数据失败')
}
})
},
ifcollection() {
this.iscollection = !this.iscollection
var val = {
user_name: localStorage.username,
news_id: this.id,
action_time: Date.now(),
action_type: `collections:${this.iscollection}`,
}
this.axios.post("/recsys/action", val).then(resource => {
if (resource.status === 200) {
// this.news_content = resource.data.data
// console.log(this.news_content)
} else {
Toast('加载数据失败')
}
})
}
},
created() {
this.getNewsInfo()
this.sendInfo()
console.log(this.$route.params);
},
components: {
// Comment
// bottomBarVue
},
beforeRouteLeave(to, from, next) {
//设置下一个路由的meta,让列表页面缓存,即不刷新
to.meta.keepAlive = true
next()
},
}
</script>
<style scoped>
/* 标题 */
.newsTitle {
padding: 3.5rem 1.5rem 0 1.5rem;
}
/* 大标题 */
.newsTitle h1 {
font-size: 16px;
line-height: 2rem;
}
/* 副标题 */
.newsTitle p {
font-size: 12px;
display: flex;
justify-content: space-between;
padding-top: 1rem;
color: #226aff;
}
/* 内容 距离底部padding 遮挡action */
.newsinfo-continer[data-v-6bb6e9d1] {
padding-bottom: 5rem;
background-color: white;
}
/* 具体内容 */
.content {
font-size: 14px;
padding: 0 20px 20px 20px;
text-indent: 2em;
/* 首行文本缩进 */
line-height: 2.2rem;
}
/* 责任编辑 */
.editor {
font-size: 14px;
padding: 0 20px 0 20px;
line-height: 2.2rem;
text-align: end;
}
#action {
/* margin: 20px 0 20px 0; */
display: flex;
justify-content: space-evenly;
}
#action>span {
display: inline-block;
padding-top: 2rem;
padding-bottom: 2rem;
font-size: 14px;
}
.blank {
width: 100vw;
height: 50px;
position: fixed;
bottom: 0;
background-color: white;
}
</style>

View File

@@ -0,0 +1,228 @@
<template>
<div>
<van-tabs sticky swipeable @scroll="scrollLength" @click="onClick">
<van-tab title="推荐">
<van-list v-model="vanListLoading" :finished="finished" :finished-text="finishedText" @load="onLoad" :offset=300>
<van-cell v-for="item in recContent" :key="item.news_id">
<!-- 路由地址传参,需要前面加表示这个参数不是字符串 -->
<router-link :to="{name:'NewsInfo' ,params:{id:item.news_id,likes:item.likes,collections:item.collections,cate:item.cate}}">
<div>
<p>
<span class="cate">{{item.cate}}</span>
<span class='title'>{{ item.title }}</span>
</p>
<p class="discribe">
<!-- <span class="ctime">发表时间{{ item.ctime}} </span> -->
<span class="read_num">阅读{{item.read_num}}</span>
<span class="likes">喜欢:{{item.likes}}</span>
<span class="collections">收藏:{{item.collections}}</span>
</p>
</div>
</router-link>
</van-cell>
</van-list>
</van-tab>
<van-tab title="热门">
<van-list v-model="vanListLoading2" :finished="finished2" :finished-text="finishedText2" @load="onLoad2" :offset=300>
<van-cell v-for="item in hotContent" :key="item.news_id">
<!-- 路由地址传参,需要前面加表示这个参数不是字符串 -->
<router-link :to="{name:'NewsInfo' ,params:{id:item.news_id,likes:item.likes,collections:item.collections,cate:item.cate}}">
<div>
<p>
<span class="cate">{{item.cate}}</span>
<span class='title'>{{ item.title }}</span>
</p>
<p class="discribe">
<!-- <span class="ctime">发表时间{{ item.ctime}} </span> -->
<span class="read_num">阅读{{item.read_num}}</span>
<span class="likes">喜欢:{{item.likes}}</span>
<span class="collections">收藏:{{item.collections}}</span>
</p>
</div>
</router-link>
</van-cell>
</van-list>
</van-tab>
</van-tabs>
<bottomBarVue></bottomBarVue>
</div>
</template>
<script>
import bottomBarVue from './bottomBar.vue'
import {
Toast
} from 'mint-ui'
export default {
data() {
return {
recContent: [],
hotContent: [],
clickNum: 0,
isActive: true,
vanListLoading: false, // 加载状态
finished: false, // 是否加载
finishedText: '', // 加载完成后的提示文案
page: 0, // 页数
vanListLoading2: false, // 加载状态
finished2: false, // 是否加载
finishedText2: '', // 加载完成后的提示文案
page2: 0, // 页数
scrollIn: 0, //进入页面时滚动条位置
scrollOut: 0, //离开页面时滚动条位置
scrollTop: 0, //滚动时触发,具体顶部的距离
}
},
components: {
bottomBarVue
},
methods: {
getNewsList(val) {
if (val === 0) {
let userId = localStorage.username,
pageId = this.recContent.length / 10 + 1
let url = '/recsys/rec_list?' + 'user_id=' + userId + '&page_id=' + pageId
this.axios.get(url).then(resource => {
if (resource.status === 200) {
this.recContent.push(...resource.data.data)
} else {
Toast('加载数据失败')
}
})
}
this.isActive = true
},
getHotList(val) {
if (val === 0) {
let userId = localStorage.username,
pageId = this.hotContent.length / 10 + 1
let url = '/recsys/hot_list?' + 'user_id=' + userId + '&page_id=' + pageId
console.log(url)
this.axios.get(url).then(resource => {
if (resource.status === 200) {
this.hotContent.push(...resource.data.data)
console.log(this.hotContent)
} else {
Toast('加载数据失败')
}
})
}
this.isActive = false
},
/*删除cookie*/
quit() {
delCookie('username')
},
getList() {
let userId = localStorage.username,
// pageId = this.recContent.length / 10 + 1
pageId = this.page
let url = '/recsys/rec_list?' + 'user_id=' + userId + '&page_id=' + pageId;
this.axios.get(url).then(res => {
if (res.status === 200) {
this.recContent.push(...res.data.data)
this.vanListLoading = false
}
})
},
onLoad() {
this.page++;
this.getList();
this.isActive = true
},
// 热门
getList2() {
let userId2 = localStorage.username,
pageId2 = this.page2
let url2 = '/recsys/hot_list?' + 'user_id=' + userId2 + '&page_id=' + pageId2;
this.axios.get(url2).then(res => {
if (res.status === 200) {
this.hotContent.push(...res.data.data)
this.vanListLoading2 = false
}
})
},
onLoad2() {
console.log('load2',this.page2);
this.page2++;
this.getList2();
this.isActive = false
},
scrollLength(res) {
this.scrollTop = res.scrollTop
},
onClick(name, title) {
console.log(this.scrollTop, '11');
document.body.scrollTop = this.scrollTop;
}
},
watch: {},
computed: {
isback() {
return this.$route.path !== '/HomeContainer'
}
},
activated() {
// 进入该组件后读取数据变量设置滚动位置
this.scrollIn = document.body.scrollTop;
document.body.scrollTop = this.scrollOut;
console.log(this.scrollIn, this.scrollOut, 'scroll-activated');
},
beforeRouteLeave(to, from, next) {
// 离开组件时保存滚动位置
// 注意, 此时需调用路由守卫`beforeRouterLeave`而非生命周期钩子`deactivated`
// 因为, 此时利用`deactivated`获取的 DOM 信息已经是新页面得了
this.scrollOut = document.body.scrollTop;
console.log(this.scrollIn, this.scrollOut, 'scroll-leave');
next();
},
}
</script>
<style scoped>
.title {
font-size: 1.2rem;
color: black;
font-weight: bolder;
}
.cate {
font-size: 1rem;
color: #00F;
margin-right: .5rem;
padding: .08rem;
border: 1px solid #00F
}
.discribe {
display: flex;
justify-content: space-between;
font-size: 1rem;
}
.read_num{
margin-right: 100px;
}
.ctime {}
.likes {}
.collections {}
</style>

View File

@@ -0,0 +1,41 @@
<template>
<div class="bottomBar">
<router-view />
<van-tabbar route>
<van-tabbar-item icon="home-o" replace to="/NewsLists">首页</van-tabbar-item>
<van-tabbar-item icon="friends-o" replace to="/Myself">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script>
export default {
name: 'bottomBar',
data() {
return {
flag: false,
}
},
methods: {
goBack() {
// 利用vue路由里的go对象-1进行往前返回的跳转
this.$router.go(-1)
},
},
computed: {
isback() {
return this.$route.path !== '/HomeContainer'
}
}
}
</script>
<style scoped>
.bottomBar {
position: fixed;
bottom: 0px;
width: 100vw;
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<div class="login-container">
<ul class="login-nav">
<li class="login-nav__item active">
<a @click="$router.push('/')">登录</a>
</li>
<li class="login-nav__item">
<a @click="$router.push('/signUp')">注册</a>
</li>
</ul>
<label for="login-input-user" class="login__label">
用户名
</label>
<van-field v-model="model.username" placeholder="请输入用户名" />
<label for="login-input-password" class="login__label">
密码
</label>
<van-field v-model="model.passwd" placeholder="请输入密码" type="password" />
<van-checkbox v-model="checked" shape="square" icon-size="15px" checked-color="#26a2ff" class="login__label--checkbox">记住我</van-checkbox>
<button class="login__submit" @click="login">登录</button>
<a href="#" class="login__forgot">忘记密码?</a>
</div>
</template>
<script>
import {
DatetimePicker,
Toast,
Popup,
Picker
} from 'mint-ui';
export default {
data() {
return {
model: {
username: '',
passwd: '',
},
val: 'login',
isLogin: true,
sexVisible: false, //选择器的显示与影藏
slots: [{
flex: 1,
values: ['male', 'female'],
className: 'slot1',
textAlign: 'center',
flex: 1
}
],
checked: false,
city: []
// sex: '男'
}
},
methods: {
login() {
let url = '/recsys/'
let state = this.val
url += state
console.log(url)
// console.log(this.model);
let res = {username: this.model.username, passwd: this.model.passwd}
this.axios.post(url, res).then(resource => {
if (resource.data.code === 200) {
let loginInfo = {
LoginName: res.username,
openId: "asfafsfsfsdfsdfsdfdsf"
}
if(this.checked){
// 调用setCookie方法同时传递需要存储的数据保存天数
this.cookie.setCookie(loginInfo, 7)
}else{
this.cookie.setCookie(loginInfo, 1)
}
localStorage.username = res.username
this.$router.push('/NewsLists')
}if(resource.data.code === 500){
Toast('登陆失败')
}if(resource.data.code === 501){
Toast('密码输入错误')
}if(resource.data.code === 502){
Toast('用户名不存在')
}
})
},
},
}
</script>
<style scoped>
/* 登录和注册的切换 */
.login-nav {
margin: 0 0 6em 1rem;
}
/* container */
.login-container {
height: 100vh;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1;
letter-spacing: 1px;
display: block;
position: relative;
z-index: 0;
background-image: url(https://img0.baidu.com/it/u=3564438015,1736378667&fm=26&fmt=auto);
background-repeat: no-repeat;
background-attachment: fixed;
background-size: 100% 100%;
background-color: black;
padding: 4rem 4rem 4rem 4rem;
}
/* 登录和注册的切换 */
.login-nav {
position: relative;
padding: 0;
}
.login-nav__item {
list-style: none;
display: inline-block;
}
.login-nav__item+.login-nav__item {
margin-left: 2.25rem;
}
.login-nav__item a {
position: relative;
color: rgba(255, 255, 255, 0.5);
text-decoration: none;
text-transform: uppercase;
font-weight: 500;
font-size: 1.25rem;
padding-bottom: .5rem;
transition: .20s all ease;
}
.login-nav__item.active a,
.login-nav__item a:hover {
color: #ffffff;
transition: .15s all ease;
}
.login-nav__item a:after {
content: '';
display: inline-block;
height: 10px;
background-color: rgb(255, 255, 255);
position: absolute;
right: 100%;
bottom: -1px;
left: 0;
border-radius: 50%;
transition: .15s all ease;
}
.login-nav__item a:hover:after,
.login-nav__item.active a:after {
background-color: rgb(17, 97, 237);
height: 2px;
right: 0;
bottom: 2px;
border-radius: 0;
transition: .20s all ease;
}
/* label标签 */
.login__label {
display: block;
padding-left: 1rem;
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
font-size: .75rem;
margin-bottom: 1rem;
}
.login__label {
margin-top: 1.5rem;
}
/* 提交按钮 */
.login__submit {
color: #ffffff;
font-size: 1rem;
font-family: 'Montserrat', sans-serif;
text-transform: uppercase;
letter-spacing: 1px;
margin-top: 2rem;
padding: .75rem;
border-radius: 2rem;
display: block;
width: 100%;
background-color: rgba(17, 97, 237, .75);
border: none;
cursor: pointer;
}
.login__submit:hover {
background-color: rgba(17, 97, 237, 1);
}
.login__label{
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
font-size: .75rem;
margin-bottom: 1rem;
}
.login__label--checkbox {
font-size: .75rem;
margin-bottom: 1rem;
display: flex;
position: relative;
margin-top: 2rem;
}
.login__input--checkbox {
position: absolute;
top: .1rem;
left: 0;
margin: 0;
}
.login__forgot {
display: block;
margin-top: 3rem;
text-align: center;
color: rgba(255, 255, 255, 0.75);
font-size: .75rem;
text-decoration: none;
position: relative;
z-index: 1;
}
.login__forgot:hover {
color: rgb(17, 97, 237);
}
</style>

View File

@@ -0,0 +1,336 @@
<template>
<div class="login-container">
<ul class="login-nav">
<li class="login-nav__item">
<a @click="$router.push('/')">登录</a>
</li>
<li class="login-nav__item active">
<a @click="$router.push('/signUp')">注册</a>
</li>
</ul>
<label for="login-input-user" class="login__label">
用户名
</label>
<van-field v-model="model.username" placeholder="请输入用户名" required @blur='ruleName(model.username)' />
<span class="errorMessage">{{message.username}}</span>
<label for="login-input-password" class="login__label">
密码
</label>
<van-field v-model="model.passwd" placeholder="请输入密码" type="password" required @blur='rulePasswd(model.passwd)' />
<span class="errorMessage">{{message.passwd}}</span>
<label for="login-input-user" class="login__label">
验证密码
</label>
<van-field v-model="model.passwd2" placeholder="再次输入密码" type="password" required @blur='rulePasswd2(model.passwd2)' />
<span class="errorMessage">{{message.passwd2}}</span>
<label for="login-input-user" class="login__label">
年龄
</label>
<van-field v-model="model.age" placeholder="请输入年龄" required @blur='ruleAge(model.age)' />
<span class="errorMessage">{{message.age}}</span>
<label for="login-input-user" class="login__label">
性别
</label>
<van-radio-group class="login__label_male" v-model="model.gender" direction="horizontal" icon-size='16px'>
<van-radio name="male"></van-radio>
<van-radio name="female"></van-radio>
</van-radio-group>
<label for="login-input-user" class="login__label">
城市
</label>
<van-field readonly clickable name="area" :value="model.city" placeholder="点击选择省市" @click="showArea = true" />
<van-popup v-model="showArea" position="bottom">
<van-area :area-list="areaList" @confirm="onConfirm" @cancel="showArea = false" :columns-num="2" />
</van-popup>
<button class="login__submit" @click="login">注册</button>
</div>
</template>
<script>
import {
areaList
} from '@vant/area-data';
import {
Toast,
} from 'mint-ui';
export default {
data() {
return {
model: {
username: '',
passwd: '',
passwd2: '',
city: '',
age: '',
gender: 'male',
},
state: '',
message: {
username: '',
passwd: '',
passwd2: '',
age: ''
},
val: 'register',
isLogin: true,
sexVisible: false, //选择器的显示与影藏
slots: [{
flex: 1,
values: ['male', 'female'],
className: 'slot1',
textAlign: 'center',
flex: 1
}
],
city: [],
showArea: false,
areaList
}
},
methods: {
login() {
let url = '/recsys/'
let state = this.val
url += state
let res = this.model
if(this.state){
this.axios.post(url, res).then(resource => {
if (resource.data.code === 200) {
console.log(resource);
localStorage.username = res.username
let loginInfo = {
LoginName: res.username,
openId: "asdasdadasdasdadad"
}
// 调用setCookie方法同时传递需要存储的数据保存天数
this.cookie.setCookie(loginInfo, 7)
localStorage.username = res.username
console.log(resource)
this.$router.push('/NewsLists')
}if(resource.data.code === 500) {
Toast('用户名已存在')
}
})
}
},
getCity(city) {
//处理选择的城市
this.model.city = city.join('-')
console.log(this.model) //得到选择的城市数据
},
// 验证用户名
ruleName(val) {
var nameReg = /^[A-Za-z0-9]+$/
if (val == '') {
this.message.username = '请输入用户名'
this.state = false
return false
} else
if (!nameReg.test(val)) {
this.message.username = '用户名格式为字母和数字'
this.state = false
return false
} else {
this.message.username = ''
this.state = true
}
},
// 验证密码
rulePasswd(val) {
var reg = /^[A-Za-z0-9]{6,}$/
if (val == '') {
this.message.passwd = '请输入密码'
this.state = false
return false
} else
if (!reg.test(val)) {
this.message.passwd = '密码长度至少6位仅包括为字母和数字'
this.state = false
return false
} else {
this.message.passwd = ''
this.state = true
}
},
//验证密码是否一致
rulePasswd2(val) {
if (val == '') {
this.message.passwd2 = '请再次输入密码'
this.state = false
return false
} else
if (val !== this.model.passwd) {
this.message.passwd2 = '两次输入的密码不正确'
this.state = false
return false
} else {
this.message.passwd2 = ''
this.state = true
}
},
//验证年龄
ruleAge(val) {
var ageReg = /^\+?[1-9][0-9]*$/
if (val == '') {
this.message.age = '请输入年龄'
this.state = false
return false
} else
if (!ageReg.test(val)) {
this.message.age = '请输入大于零的整数'
this.state = false
return false
} else {
this.message.age = ''
this.state = true
}
},
onConfirm(values) {
let pinyin = require('js-pinyin');
this.model.city = values[1].name.slice(0, values[1].name.length - 1) //过滤到市级,删除‘市’
this.model.city = pinyin.getFullChars(this.model.city) //将汉字转换为拼音
this.showArea = false;
},
}
}
</script>
<style scoped>
/* 错误信息提示 */
.errorMessage {
color: red;
font-size: .8rem;
display: block;
padding: 1rem 0 0 1rem;
}
/* container */
.login-container {
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1;
letter-spacing: 1px;
display: block;
position: relative;
z-index: 0;
background-image: url(https://img0.baidu.com/it/u=3564438015,1736378667&fm=26&fmt=auto);
background-repeat: no-repeat;
background-attachment: fixed;
background-size: 100% 100%;
background-color: black;
padding: 4rem 4rem 4rem 4rem;
}
/* 登录和注册的切换 */
.login-nav {
position: relative;
padding: 0;
margin: 0 0 3em 1rem;
}
.login-nav__item {
list-style: none;
display: inline-block;
}
.login-nav__item+.login-nav__item {
margin-left: 2.25rem;
}
.login-nav__item a {
position: relative;
color: rgba(255, 255, 255, 0.5);
text-decoration: none;
text-transform: uppercase;
font-weight: 500;
font-size: 1.25rem;
padding-bottom: .5rem;
transition: .20s all ease;
}
.login-nav__item.active a,
.login-nav__item a:hover {
color: #ffffff;
transition: .15s all ease;
}
.login-nav__item a:after {
content: '';
display: inline-block;
height: 10px;
background-color: rgb(255, 255, 255);
position: absolute;
right: 100%;
bottom: -1px;
left: 0;
border-radius: 50%;
transition: .15s all ease;
}
.login-nav__item a:hover:after,
.login-nav__item.active a:after {
background-color: rgb(17, 97, 237);
height: 2px;
right: 0;
bottom: 2px;
border-radius: 0;
transition: .20s all ease;
}
/* label标签 */
.login__label {
display: block;
padding-left: 1rem;
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
font-size: .75rem;
margin-bottom: 1rem;
}
.login__label {
margin-top: 1.5rem;
}
/* 提交按钮 */
.login__submit {
color: #ffffff;
font-size: 1rem;
font-family: 'Montserrat', sans-serif;
text-transform: uppercase;
letter-spacing: 1px;
margin-top: 2rem;
padding: .75rem;
border-radius: 2rem;
display: block;
width: 100%;
background-color: rgba(17, 97, 237, .75);
border: none;
cursor: pointer;
}
.login__submit:hover {
background-color: rgba(17, 97, 237, 1);
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Fun-Rec</title>
<script src="//at.alicdn.com/t/font_2884515_cx2xhya52r9.js"></script>
</head>
<body style="background-color: #fff;">
<div id="app" >
</div>
</body>
</html>

View File

@@ -0,0 +1,63 @@
@font-face {
font-family: MuiiconSpread;
font-weight: normal;
font-style: normal;
src: url('../fonts/mui-icons-extra.ttf') format('truetype'); /* iOS 4.1- */
}
.mui-icon-extra
{
font-family: MuiiconSpread;
font-size: 24px;
font-weight: normal;
font-style: normal;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
}
.mui-icon-extra-cold:before { content: "\e500"; }
.mui-icon-extra-share:before { content: "\e200"; }
.mui-icon-extra-class:before { content: "\e118"; }
.mui-icon-extra-custom:before { content: "\e117"; }
.mui-icon-extra-new:before { content: "\e103"; }
.mui-icon-extra-card:before { content: "\e104"; }
.mui-icon-extra-grech:before { content: "\e105"; }
.mui-icon-extra-trend:before { content: "\e106"; }
.mui-icon-extra-filter:before { content: "\e207"; }
.mui-icon-extra-holiday:before { content: "\e300"; }
.mui-icon-extra-cart:before { content: "\e107"; }
.mui-icon-extra-heart:before { content: "\e180"; }
.mui-icon-extra-computer:before { content: "\e600"; }
.mui-icon-extra-express:before { content: "\e108"; }
.mui-icon-extra-gift:before { content: "\e109"; }
.mui-icon-extra-gold:before { content: "\e102"; }
.mui-icon-extra-lamp:before { content: "\e601"; }
.mui-icon-extra-rank:before { content: "\e110"; }
.mui-icon-extra-notice:before { content: "\e111"; }
.mui-icon-extra-sweep:before { content: "\e202"; }
.mui-icon-extra-arrowleftcricle:before { content: "\e401"; }
.mui-icon-extra-dictionary:before { content: "\e602"; }
.mui-icon-extra-heart-filled:before { content: "\e119"; }
.mui-icon-extra-xiaoshuo:before { content: "\e607"; }
.mui-icon-extra-top:before { content: "\e403"; }
.mui-icon-extra-people:before { content: "\e203"; }
.mui-icon-extra-topic:before { content: "\e603"; }
.mui-icon-extra-hotel:before { content: "\e301"; }
.mui-icon-extra-like:before { content: "\e206"; }
.mui-icon-extra-regist:before { content: "\e201"; }
.mui-icon-extra-order:before { content: "\e113"; }
.mui-icon-extra-alipay:before { content: "\e114"; }
.mui-icon-extra-find:before { content: "\e400"; }
.mui-icon-extra-arrowrightcricle:before { content: "\e402"; }
.mui-icon-extra-calendar:before { content: "\e115"; }
.mui-icon-extra-prech:before { content: "\e116"; }
.mui-icon-extra-cate:before { content: "\e501"; }
.mui-icon-extra-comment:before { content: "\e209"; }
.mui-icon-extra-at:before { content: "\e208"; }
.mui-icon-extra-addpeople:before { content: "\e204"; }
.mui-icon-extra-peoples:before { content: "\e205"; }
.mui-icon-extra-calc:before { content: "\e101"; }
.mui-icon-extra-classroom:before { content: "\e604"; }
.mui-icon-extra-phone:before { content: "\e404"; }
.mui-icon-extra-university:before { content: "\e605"; }
.mui-icon-extra-outline:before { content: "\e606"; }

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,132 @@
// 导入vue
import Vue from 'vue'
// 导入根组件
import App from './App.vue'
// 导入路由
import VueRouter from 'vue-router'
Vue.use(VueRouter);
// 导入axios,axios不是一个插件所以不能Vue.use使用vue-axios是个插件。
import axios from 'axios'
import VueAxios from 'vue-axios'
// Vue.prototype.$http = axios
Vue.use(VueAxios, axios);
// axios公共基路径以后所有的请求都会在前面加上这个路径
axios.defaults.baseURL = "http://10.170.4.60:3000";
// 设置表单提交方式,默认是 json
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
// 请求超时时间
// axios.defaults.timeout=5000;
// 导入缩略图插件
import VuePreview from 'vue-preview'
Vue.use(VuePreview);
// 导入Vue的组件
import routerObj from './router.js'
// 全局组件
// 时间过滤组件
import moment from 'moment' // node的一个时间格式化插件
// 定义全局时间过滤的组件
Vue.filter('timeFormat', function (dataStr, pattern = "YYYY-MM-DD HH:mm:ss") {
return moment(dataStr).format(pattern)
});
// 三方组件
// 导入mint-ui组件,不建议全部导入体积太大
// 按需导入先安装babel-plugin-component,然后在.babelrc加上官网说的配置加载css,如下
import Mint from 'mint-ui';
import CityPicker from 'vue-addr-picker';
Vue.use(CityPicker)
Vue.use(Mint);
import 'mint-ui/lib/style.css'
// 导入mui的css样式
import './lib/mui/css/mui.css'
import './lib/mui/css/icons-extra.css'
// import { Field } from 'mint-ui';
// Vue.component(Field.name, Field);
// import './assets/css/index.less'
import { Form } from 'vant';
import { Field } from 'vant';
import { RadioGroup, Radio } from 'vant';
import 'vant/lib/radio/style'
import 'vant/lib/radio-group/style'
import { Area } from 'vant';
import 'vant/lib/area/style'
import { Popup } from 'vant';
import 'vant/lib/popup/style'
Vue.use(Popup);
Vue.use(Area);
Vue.use(Form);
Vue.use(Field);
Vue.use(Radio);
Vue.use(RadioGroup);
import { Checkbox } from 'vant';
Vue.use(Checkbox);
import { List } from 'vant';
Vue.use(List);
import { Cell } from 'vant'
Vue.use(Cell)
import { PullRefresh } from 'vant'
Vue.use(PullRefresh)
import { Tab, Tabs } from 'vant';
import 'vant/lib/tab/style'
import 'vant/lib/tabs/style'
Vue.use(Tab);
Vue.use(Tabs);
import { Tabbar, TabbarItem } from 'vant';
import 'vant/lib/tabbar/style'
import 'vant/lib/tabbar-item/style'
Vue.use(Tabbar);
Vue.use(TabbarItem);
import { NavBar } from 'vant';
import 'vant/lib/nav-bar/style'
Vue.use(NavBar);
import { Button } from 'vant';
import 'vant/lib/button/style'
Vue.use(Button);
Vue.config.devtools = false; //生产环境中需要设置为false
Vue.config.productionTip = false; //阻止vue启动时生成生产消息
import cookie from './assets/js/cookie'
Vue.prototype.cookie = cookie
// 创建vue对象
let vm = new Vue({
el: '#app',
data() {
return {}
},
methods: {},
render: c => c(App),
router: routerObj
});

View File

@@ -0,0 +1,123 @@
// 导入VueRoute路由组件
import VueRouter from 'vue-router'
//导入cookie
import cookie from './assets/js/cookie'
import Myself from "./components/Myself.vue";
// 新闻组件
import NewsLists from "./components/NewsLists.vue";
import NewsInfo from "./components/NewsInfo.vue";
import Login from './components/Login.vue'
import signIn from './components/signIn.vue'
import signUp from './components/signUp.vue'
let routerObj = new VueRouter({
// mode: 'history',
routes: [
{
path: '/',
component: signIn,
meta: {
isPublic: true,
keepAlive: false,
scrollTop: 0
},
},
{
path: '/signUp',
component: signUp,
meta: {
isPublic: true,
keepAlive: false,
scrollTop: 0
},
},
{
path: '/NewsLists',
component: NewsLists,
meta: {
isPublic: false,
keepAlive: true,
scrollTop: 0
}
},
{
path: '/Myself',
component: Myself,
meta: {
isPublic: false,
keepAlive: false,
scrollTop: 0
},
},
{
path: '/NewsInfo/:id',
name: 'NewsInfo',
component: NewsInfo,
meta: {
isPublic: false,
keepAlive: false,
scrollTop: 0
}
},
],
linkActiveClass: 'mui-active',
})
// 解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
// 未登录直接跳转至登录页
// routerObj.beforeEach(async (to, from, next) => {
// console.log(localStorage.tokens)
// if (!to.meta.isPublic && !localStorage.username) {
// return next('/login')
// }
// next()
// })
/*
* beforeEach:从一个页面跳转到另外一个页面时触发
* to:要跳转的页面
* from:从哪个页面出来
* next:决定是否通过
*/
/* router.beforeEach意思是在router.index设置了一个全局守卫
只要发生页面跳转,会执行里面的代码,首先先去判断跳转的页面是否存在,
调用cookie.getCookie()方法读取用户信息,
如果不存在代表没有登录用next('/Login')进入Login登录页面进行登录
如果读取到了用户信息,不做拦截直接放行。 */
routerObj.beforeEach((to, from, next) => {
if (cookie.getCookie("openId")) {
next()
} else {
if (to.path === "/") {
next()
} if (to.path == '/signUp') {
next()
} else {
next('/')
}
}
// if (from.meta.keepAlive) {
// const $wrapper = document.querySelector('.van-tabs__content'); // 列表的外层容器 注意找到滚动的盒子
// console.log($wrapper);
// const scrollTop = $wrapper ? $wrapper.scrollTop : 0;
// console.log('scrollTop=', scrollTop)
// from.meta.scrollTop = scrollTop;
// }
// next();
})
// 把routerObj对象暴漏出去。main.js导入这个数据
export default routerObj

View File

@@ -0,0 +1,22 @@
module.exports = {
publicPath: './', // 基本路径
outputDir: 'dist', // 输出文件目录
assetsDir: "static", //放置生成的静态文件目录js css img
productionSourceMap: false, // 生产环境是否生成 sourceMap 文件
chainWebpack: config => {
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
},
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {// 为生产环境修改配置...
config.mode = 'production';
config["performance"] = {//打包文件大小配置
"maxEntrypointSize": 10000000,
"maxAssetSize": 30000000
}
}
}
}

View File

@@ -0,0 +1,110 @@
// 导入处理路径的模块
const path = require('path');
// 导入在内存中生成 HTML 页面的 插件
// 只要是插件,都一定要 放到 plugins 节点中去
// 这个插件的两个作用:
// 1. 自动在内存中根据指定页面生成一个内存的页面
// 2. 自动,把打包好的 bundle.js 追加到页面中去
const htmlWebpackPlugin = require('html-webpack-plugin');
// 配置vue这个插件是必须的 它的职责是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,如果你有一条匹配 /\.js$/ 的规则,那么它会应用到 .vue 文件里的 <script> 块。
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// 引入 ParallelUglifyPlugin 插件
// const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
// 这个配置文件,起始就是一个 JS 文件,通过 Node 中的模块操作,向外暴露了一个 配置对象
module.exports = {
mode: 'production', // 生产环境下会自动压缩js代码
// productionSourceMap: false,
// path.join拼接入口文件
entry: path.join(__dirname, './src/main.js'),// 入口,表示,要使用 webpack 打包哪个文件
output: { // 定义出口文件
path: path.join(__dirname, './dist'), // 指定 打包好的文件,输出到哪个目录中去
filename: 'bundle.js' // 这是指定 输出的文件的名称
},
// 配置插件的节点
plugins: [
// 创建一个在内存中生成HTML页面的插件,指定模板页面将来会根据指定的页面路径去生成内存中的index.html,并且自动加载内存中的bundle.js文件。
new htmlWebpackPlugin({
template: path.join(__dirname, './src/index.html'),
filename: 'index.html' // 指定生成的页面的名称
}),
// 请确保引入这个插件!
new VueLoaderPlugin(),
// // 使用 ParallelUglifyPlugin 并行压缩输出JS代码
// new ParallelUglifyPlugin({
// // 传递给 UglifyJS的参数如下
// uglifyJS: {
// output: {
// /*
// 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
// 可以设置为false
// */
// beautify: false,
// /*
// 是否保留代码中的注释默认为保留为了达到更好的压缩效果可以设置为false
// */
// comments: false
// },
// compress: {
// /*
// 是否在UglifyJS删除没有用到的代码时输出警告信息默认为输出可以设置为false关闭这些作用
// 不大的警告
// */
// warnings: false,
// /*
// 是否删除代码中所有的console语句默认为不删除开启后会删除所有的console语句
// */
// drop_console: true,
// /*
// 是否内嵌虽然已经定义了,但是只用到一次的变量,比如将 var x = 1; y = x, 转换成 y = 5, 默认为不
// 转换为了达到更好的压缩效果可以设置为false
// */
// collapse_vars: true,
// /*
// 是否提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx' 转换成
// var a = 'xxxx'; x = a; y = a; 默认为不转换为了达到更好的压缩效果可以设置为false
// */
// reduce_vars: true
// }
// },
// sourceMap: false
// }),
],
module: {
rules: [ // 文件匹配规则use代表使用那些模块来处理test所匹配的文件。use中模块的加载顺序是从后到前。
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 处理css的文件的规则--实施加载
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, // 处理less文件的规则
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, // 处理sass文件的规则
// 处理图片的loader,如果字节小于7631转成base64位,name可选参数代表图片的名字,后面参数拼接图片的名字8位base64+图片名称
{ test: /\.(png|jpg|gif)$/, use: 'url-loader?limit=7631&name=images/[hash:8]-[name].[ext]' },
{ test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader' }, // 处理字体文件的 loader (bootstrap字体图标)
// 用来处理ES6或者ES7高级语法的loader,相当于一个转换器。会把高级语法转换成ES5浏览器能识别的JS代码
// 注参数里exclude: 表示不转换的文件夹。|需要创建.babelrc配置文件里面配置转换插件的字典和工具
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
// 添加支持vue的loader
{ test: /\.vue$/, use: 'vue-loader' }
]
},
resolve: {
alias: { // 设置 Vue 被导入时候的包的路径,一种更方便使用import form导入包得方式
"vue$": "vue/dist/vue.js"
}
},
// dev: {
// host: '0.0.0.0'
// }
};