增加新项目

This commit is contained in:
2025-03-16 23:01:07 +08:00
parent 3f86afc191
commit 353b15385f
49 changed files with 4407 additions and 2 deletions

Submodule 历届学生/樊明宇 added at 94d42d63b1

Submodule 历届学生/王智伟 added at 44195c16e7

View File

@@ -1 +0,0 @@
e00b97af-e54e-43df-a865-8050026500e0

View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,15 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: myclone
image: 2271608011/bmygit:v1.2
network_mode: host
commands:
- echo "192.168.31.100 git.buyusdt.xyz" >> /etc/hosts
- git clone https://git.buyusdt.xyz/bmy/xiezheng.git
- cd /drone/src/xiezheng/ && npm install && npm run dev && npm run log

View File

@@ -0,0 +1,67 @@
import express from "express";
import config from "./config/config.js";
import { ipv6, ipv4 } from "./utils/ip.js";
import tagsRouter from "./router/tags.js";
import infoRouter from "./router/info.js";
import searchRouter from "./router/search.js";
import homeRouter from "./router/home.js";
import hotRouter from "./router/hot.js";
import http from "http";
const app = express()
//解决跨域
app.use((req, res, next) => {
// 设置是否运行客户端设置 withCredentials
// 即在不同域名下发出的请求也可以携带 cookie
res.header("Access-Control-Allow-Credentials", true)
// 第二个参数表示允许跨域的域名,* 代表所有域名
res.header('Access-Control-Allow-Origin', '*')//配置80端口跨域
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, OPTIONS') // 允许的 http 请求的方法
// 允许前台获得的除 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 这几张基本响应头之外的响应头
res.header('Access-Control-Allow-Headers', '*')
if (req.method == 'OPTIONS') {
res.sendStatus(200)
} else {
next()
}
})
app.use('/v1/api/tag', tagsRouter);
app.use('/v1/api/info', infoRouter);
app.use('/v1/api/search', searchRouter);
app.use('/v1/api/home', homeRouter);
app.use('/v1/api/hot', hotRouter);
http.createServer(app).listen(config.port, "::",() => {
console.log(`
爬虫运行在下面网址:
1⃣ 公网 IPV6: http://[${ipv6()}]:${config.port}
2⃣ 局域网 IPV4: http://${ipv4()}:${config.port}
`)
})
// error handler
app.use(function(err, req, res, next) {
console.log(`
程序出现错误
status信息为${err.status}
message信息为${err.message}
error为${err}
`)
});
// app.listen(config.port, () => {
// console.log(`
// 爬虫运行在下面网址:
// 1⃣ 公网 IPV6: http://[${ipv6()}]:${config.port}
// 2⃣ 局域网 IPV4: http://${ipv4()}:${config.port}
// `)
// })
export default app

View File

@@ -0,0 +1,8 @@
export default {
port: 9940,
proxyPort: 7890,
baseUrl: 'https://www.06se.com',
hot_tags: function () {
return `${this.baseUrl}/hot_tags`
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
{
"name": "newbackapi",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "./node_modules/.bin/pm2 start app.js --stop-exit-codes 0",
"stop": "./node_modules/.bin/pm2 stop app",
"log": "./node_modules/.bin/pm2 log",
"list": "./node_modules/.bin/pm2 list",
"monit": "pm2 monit"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.7.7",
"cheerio": "^1.0.0-rc.12",
"express": "^4.21.1",
"https-proxy-agent": "^7.0.5",
"ip": "^2.0.1",
"pm2": "^5.4.3"
}
}

View File

@@ -0,0 +1,78 @@
import express from "express";
import Util from '../utils/index.js'
import Config from '../config/config.js'
const router = express.Router();
// 获取首页banner图
// http://192.168.31.101:9940/v1/api/home/banner
router.get('/banner', async (req, res) => {
// let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
// $(".new-swiper .swiper-wrapper .swiper-slide").each(function() {
// let src = $(this).find("span img").attr("src")
// console.log("src: ", src);
// if (src) {
// result.push({ src })
// }
// })
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: [
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/54e736d12f2eb938b7ce5c2990628535e4dd6f4d.jpg' },
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/b899a9014c086e06d533199047087bf40bd1cb56.jpg' },
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/269759ee3d6d55fb6c5d50fd28224f4a21a4dd56.jpg' },
]
})
})
// 获取热门推荐的写真
// http://192.168.31.101:9940/v1/api/home/hot
router.get('/hot', async (req, res) => {
let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
let result = []
$(".box-body .tab-content .posts-mini").each(function() {
result.push({
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
title: $(this).find(".item-heading a").text(),
time: $(this).find(".item-meta .icon-circle").text(),
view: $(this).find(".item-meta .meta-right .meta-view").text()
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
// 获取首页 默认的随机写真
// http://192.168.31.101:9940/v1/api/home/list
router.get('/list', async (req, res) => {
let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
let result = []
$(".tab-content .posts-row .posts-item").each(function() {
result.push({
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
title: $(this).find(".item-heading a").text(),
time: $(this).find(".item-meta .icon-circle").text(),
view: $(this).find(".item-meta .meta-right .meta-view").text()
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
export default router

View File

@@ -0,0 +1,40 @@
import express from "express";
import Util from '../utils/index.js'
import Config from '../config/config.js'
import utils from "../utils/index.js";
const router = express.Router();
// 获取 底部导航的 热门
// http://192.168.31.101:9940/v1/api/hot/list?page=1
router.get('/list', async (req, res) => {
let { page } = req.query
page = page || 1
let $ = await Util.get(`${Config.baseUrl}/other/page/${page}`)
let result = {
currentPage: page,
totalPage: utils.maxPage(".pagenav a", $),
message: $(".search-content .badg .focus-color").text(),
list: [],
}
$(".posts-row .posts-item").each(function() {
result.list.push({
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
title: $(this).find(".item-heading a").text(),
time: $(this).find(".item-meta .icon-circle").text(),
view: $(this).find(".item-meta .meta-right .meta-view").text()
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
export default router

View File

@@ -0,0 +1,42 @@
import express from "express";
import Util from '../utils/index.js'
import Config from '../config/config.js'
const router = express.Router();
// 进入详情的接口
// http://192.168.31.101:9940/v1/api/info/list?id=6808
router.get('/list', async (req, res) => {
let { id } = req.query
let $ = await Util.get(`${Config.baseUrl}/${id}.html`)
let result = {
title: $(".article .article-header .article-title a").text(),
src_list: [],
recommend: [],
}
$(".article-content .wp-posts-content p img").map(function(i, el) {
result.src_list.push($(el).attr("data-src"))
})
$(".swiper-container .swiper-slide a").each(function(i, el) {
result.recommend.push({
id: Util.split($(this).attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find("img").attr("data-src"),
title: $(this).find(".text-ellipsis").text(),
time: $(this).find(".px12 item").eq(0).text(),
view: $(this).find(".px12 item").eq(1).text(),
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
export default router

View File

@@ -0,0 +1,70 @@
import express from "express";
import Util from '../utils/index.js'
import Config from '../config/config.js'
const router = express.Router();
// 搜索页面的 热门关键词 & 推荐
// http://192.168.31.101:9940/v1/api/search/hot
router.get('/hot', async (req, res) => {
let $ = await Util.get(`${Config.baseUrl}/wp-admin/admin-ajax.php?action=search_box`)
let result = {
hotKeyword: [],
recommend: []
}
$(".search-input .search-keywords").eq(0).find("div a").each(function() {
result.hotKeyword.push($(this).text())
})
$(".search-input .relates-thumb .swiper-slide a").each(function() {
result.recommend.push({
id: Util.split($(this).attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find("img").attr("data-src"),
title: $(this).find(".text-ellipsis").text(),
time: $(this).find(".px12 item").eq(0).text(),
view: $(this).find(".px12 item").eq(1).text(),
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
// 搜索接口
// http://192.168.31.101:9940/v1/api/search/key?keyword=杨晨晨&page=1
router.get('/key', async (req, res) => {
let { keyword, page } = req.query
page = page || 1
let $ = await Util.get(`${Config.baseUrl}/page/${page}?s=${encodeURI(keyword)}&type=post`)
let result = {
currentPage: page,
totalPage: Util.maxPage(".pagenav a", $),
message: $(".search-content .badg .focus-color").text(),
list: [],
}
$(".search-content .posts-item").each(function() {
result.list.push({
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
title: $(this).find(".item-body .item-heading a").text(),
time: $(this).find(".item-body .item-meta .icon-circle").text(),
view: $(this).find(".item-body .item-meta .meta-right .meta-view").text()
})
})
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
})
})
export default router

View File

@@ -0,0 +1,76 @@
import express from "express";
import Util from '../utils/index.js'
import Config from '../config/config.js'
const router = express.Router();
// 获取 推荐标签
// http://192.168.31.101:9940/v1/api/tag/recommend
router.get('/recommend', async (req, res) => {
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: [
{ title: '秀人网', count: '9059', url: '/xiuren', index: 0 },
{ title: 'ROSI写真', count: '6580', url: '/domestic/rosi', index: 2 },
{ title: '蜜桃社', count: '122', url: '/domestic/miitao', index: 27 },
{ title: '尤物馆', count: '138', url: '/domestic/youwu', index: 29 },
]
});
})
// 获取 所有标签
// http://192.168.31.101:9940/v1/api/tag/list
router.get('/list', async (req, res) => {
let $ = await Util.get(Config.hot_tags())
let result = []
$(".categorieslist ul li a").each(function (i) {
result.push({
title: $(this).find("h2").text(),
count: $(this).find("small p").text().replace(/[^\d]/g, ""),
url: Util.split($(this).attr("href")),
});
});
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
});
})
// 进入对应标签的列表页面
// http://192.168.31.101:9940/v1/api/tag/info?url=/xiuren&page=1
router.get('/info', async (req, res) => {
let { url, page } = req.query
page = page || 1
let $ = await Util.get(`${Config.baseUrl}${url}/page/${page}`)
let result = {
count: $(".content-layout .title-h-left .icon-spot").text().replace(/[^\d]/g, ""),
introduce: $(".content-layout .muted-2-color").text(),
totalPage: Util.maxPage(".pagenav a", $),
currentPage: page,
list: []
}
$(".content-layout .posts-row .posts-item").each(function (i) {
result.list.push({
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
title: $(this).find(".item-body .item-heading a").text(),
time: $(this).find(".item-body .item-meta .icon-circle").text(),
view: $(this).find(".item-body .item-meta .meta-right .meta-view").text()
});
});
res.json({
status: 200,
copyright: `bmy ${new Date()}`,
data: result
});
})
export default router

View File

@@ -0,0 +1,81 @@
import * as cheer from "cheerio";
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
import Config from "../config/config.js";
class utils {
constructor() {
this.ax = axios
// 让 ajax 请求 走flclash的翻墙代理
const httpsAgent = new HttpsProxyAgent(`http://127.0.0.1:${Config.proxyPort}`);
this.ax.defaults.httpsAgent = httpsAgent;
this.ax.defaults.proxy = false;
this.ResponseInterceptor()
}
/**
* 返回 cheerio 数据结构
* @param html
* @returns {*}
*/
cheerio(html) {
return cheer.load(html)
}
split(str, index = 1) {
return str.split(Config.baseUrl)[index]
}
/**
*
* @param url 请求的地址
* @returns {Promise<AxiosResponse<any>>}
*/
async get(url) {
return await this.ax.get(url, {
headers: {
'sec-ch-ua-mobile': '?1',
'sec-fetch-site': 'same-origin',
'upgrade-insecure-requests': '1',
'priority': 'u=0, i',
'sec-fetch-mode': 'navigate',
'cookie': `_ga=GA1.1.1571194344.1732275775; _lscache_vary=0e8aace2958628a1edb01710bbabbcab; showed_system_notice=showed; PHPSESSID=5jmev023fsh6i76huat60njio3; _ga_ZT9Q6FCC5R=GS1.1.1732668048.9.1.1732668791.0.0.0`,
'referer': 'https://www.06se.com/hot_tags',
'user-agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1`
}
});
}
maxPage(el, $) {
let pageArr = []
$(el).each(function() {
let page = Number($(this).text())
page ? pageArr.push(page) : null
})
return Math.max(...pageArr)
}
/**
*
* 响应拦截器
* @constructor
*/
async ResponseInterceptor() {
this.ax.interceptors.response.use((response) => {
return this.cheerio(response.data);
}, (error) => {
console.log(`
❌ 请求错误❕❕❕
1: 错误信息 ${error.message}
2: 原因目标网站禁止国内大陆IP访问爬虫会走系统代理进行请求访问
但检测到你未开启翻墙工具请打开Clash或FlClash等代理工具保证能正常访问 Google。
3: 自定义代理端口:修改代码'/config/config.js'中 proxyPort 实现自定义端口,端口从代理工具中查看
`);
return Promise.reject(error)
})
}
}
export default new utils();

View File

@@ -0,0 +1,12 @@
import ip from 'ip'
class IP {
ipv6() {
return ip.address('private','ipv6')
}
ipv4() {
return ip.address('public','ipv4')
}
}
export const {ipv6,ipv4} = new IP()

View File

@@ -0,0 +1,32 @@
body,p {
font-size: 0;
margin: 0;
line-height: 1;
}
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
color: var(--textColor);
}
input {
line-height: 0;
}
img {
width: 100%;
}
::-webkit-scrollbar {
width: 0;
height: 0;
}

View File

@@ -0,0 +1,7 @@
:root {
--whiteColor: #fff;
--textColor: #050505;
--themeColor: #fb7299;
--tipsTextColor: #929292;
--tipsBackGroundColor: #f5f5f5;
}

View File

@@ -0,0 +1,141 @@
.header {
top: 0;
left: 0;
right: 0;
width: 100%;
background: var(--whiteColor);
z-index: 999;
height: .9rem;
i {
font-size: .44rem;
}
.icon-wujiaoxing {
margin-right: .1rem;
}
.header_title {
color: var(--textColor);
font-size: .32rem;
margin: 0 .16rem;
flex: 1;
}
}
.footer {
width: 100%;
height: 1rem;
background-color: var(--whiteColor);
padding: 0 .52rem;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
li {
a {
display: flex;
align-items: center;
flex-direction: column;
i {}
div {
font-size: 0.22rem;
margin-top: 0.1rem;
}
}
}
.active {
i,
div {
color: var(--themeColor);
}
}
}
.recommend-model {
margin-top: .5rem;
.title {
height: .9rem;
font-size: .38rem;
font-weight: bolder;
}
.list {
li {
width: 3.32rem;
margin-bottom: 0.4rem;
a {
img {
width: 100%;
border-radius: 0.14rem;
margin-bottom: 0.18rem;
height: 4.98rem;
object-fit: cover;
}
.desc {
.name {
font-size: .34rem;
color: var(--textColor);
margin-bottom: 0.12rem;
}
.time {
font-size: .2rem;
color: var(--tipsTextColor);
.text {}
.view {
i {}
span {}
}
}
}
}
}
}
}
.roll {
.list {
overflow-x: scroll;
}
li {
flex-shrink: 0;
margin-right: .3rem;
&:last-child {
margin-right: 0;
}
}
}
.swiper-pagination-bullet-active {
background: var(--themeColor);
}
.content {
margin-top: .9rem;
margin-bottom: 1rem;
}
#nprogress {
.bar {
background: var(--themeColor);
height: .08rem;
.peg {
box-shadow: 0 0 10px var(--themeColor), 0 0 5px var(--themeColor)
}
}
.spinner-icon {
border-top-color: var(--themeColor);
border-left-color: var(--themeColor);
}
}

View File

@@ -0,0 +1,52 @@
.header {
height: .96rem;
.search {
height: .76rem;
width: 93%;
border-radius: .4rem;
background: var(--tipsBackGroundColor);
padding: 0px 16px;
i {
margin-right: .1rem;
}
i,
div {
font-size: .3rem;
color: var(--tipsTextColor);
}
}
}
.recommend-tag {
padding: 0 .36rem;
margin-top: .4rem;
margin-top: .5rem;
li {
a {
display: flex;
flex-direction: column;
align-items: center;
.title {
font-size: .5rem;
margin-bottom: 0.14rem;
}
.desc {
font-size: .28rem;
color: var(--tipsTextColor);
}
}
}
}
.swiper {
width: calc(100% - .56rem);
border-radius: 30px;
}
.content {
margin-top: .96rem;
}

View File

@@ -0,0 +1,31 @@
.info {
height: 18rem;
.img_arr {
img {}
}
.all {
font-size: .32rem;
color: var(--themeColor);
width: 100%;
height: 1.2rem;
bottom: 0;
left: 0;
right: 0;
padding-bottom: .2rem;
background: linear-gradient(180deg, #fcfcfc00, #ffffff);
span {
margin-right: .1rem;
}
i {}
}
}
.show {
height: auto !important;
.all {
display: none !important;
}
}

View File

@@ -0,0 +1,107 @@
.block {
display: block;
}
.flex-block {
display: flex block;
}
.none {
display: none;
}
.inline-block {
display: inline-block;
}
.flex {
display: flex;
}
.ai-c {
align-items: center;
}
.ai-e {
align-items: flex-end;
}
.jc-sb {
justify-content: space-between;
}
.jc-c {
justify-content: center;
}
.wrap {
flex-wrap: wrap;
}
.shrink {
flex-shrink: 0;
}
.x-scroll {
overflow-x: scroll;
}
.fixed {
position: fixed;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.p-l {
padding-left: 0.115rem;
}
.p-r {
padding-right: 0.12rem;
}
.border-box {
box-sizing: border-box;
}
/* 把css当成js来写 */
/* css基本上都有 */
/* .border-top(@fx: top) {
border-@fx: 1px solid #e8e8e8;
} */
.p18 {
padding: 0 .36rem;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.border-top {
border-top: 1px solid #e8e8e8;
}
.border-bottom {
border-bottom: 1px solid #e8e8e8;
}
.border-left {
border-left: 1px solid #e8e8e8;
}
.border-right {
border-right: 1px solid #e8e8e8;
}
.hidden {
overflow: hidden;
}

View File

@@ -0,0 +1,50 @@
.tabs_title {
height: 0.8rem;
top: .9rem;
z-index: 999;
background: #fff;
width: 100%;
left: 0;
right: 0;
li {
margin-right: .3rem;
flex-shrink: 0;
font-size: .28rem;
color: var(--textColor);
position: relative;
&:last-child {
margin-right: .8rem;
}
}
.active {
color: var(--themeColor);
}
.active::after {
position: absolute;
content: "";
width: .5rem;
height: .08rem;
display: inline-block;
background: var(--themeColor);
left: 50%;
transform: translateX(-50%);
bottom: -0.24rem;
border-radius: .24rem;
}
}
.swiper-slide {
height: calc(100vh - .9rem - .8rem - 1rem);
overflow-y: scroll;
}
.recommend-model {
padding-top: .2rem;
margin-top: 0;
box-sizing: border-box;
}
.content {
margin-top: 1.7rem;
}

View File

@@ -0,0 +1,60 @@
const config = {
stage: "prod", // dev test prod
// 开发阶段请求地址
devUrl: 'https://pc.buyusdt.xyz/v1/api',
// 测试阶段请求地址
testUrl: 'http://[240e:362:223f:2e00::fce]:3030/v1/test',
// 正式阶段请求地址
prodUrl: 'https://pc.buyusdt.xyz/v1/api',
urlList: {
homeHot: '/home/hot', // 获取热门推荐的写真
homeBanner: '/home/banner',
homeList: '/home/list',
tagRecommend: '/tag/recommend',
tagList: '/tag/list',
tagInfo: '/tag/info',
infoList: '/info/list',
hotList: '/hot/list',
},
footerArr: [
{ title: '首页', icon: 'icon-shouye', href: 'index.html' },
{ title: '分类', icon: 'icon-changchenglogo', href: 'type.html' },
{ title: '热门', icon: 'icon-hot', href: 'hot.html' },
{ title: '我的', icon: 'icon-wo', href: 'me.html' },
],
// 动态的返回不同阶段的项目 基地址
checkStage: function () {
switch (this.stage) {
case "dev":
return this.devUrl
break;
case "test":
return this.testUrl
break;
case "prod":
return this.prodUrl
break;
default:
break;
}
},
}
// 基(基本)地址 短地址(具体的功能地址)
// http://[240e:362:223f:2e00::fce]:3030/v1/api /home/hot
// https://pc.buyusdt.xyz/v1/api /home/hot

View File

@@ -0,0 +1,78 @@
// 用js的function 来模拟class
const http = () => {
NProgress.configure({
easing: 'ease', speed: 200,
trickleSpeed: 150
});
const init = () => {
return new XMLHttpRequest();
}
const get = (params) => {
let http = init()
NProgress.start();
return new Promise((success, error) => {
http.open("get", handleGetParams(params))
http.send()
readystatechange(http, success, error)
})
}
const post = (params) => {
let http = init()
NProgress.start();
return new Promise((success, error) => {
http.open("post", config.checkStage() + params.url)
http.setRequestHeader("Content-Type", "application/json")
http.send(JSON.stringify(params.data))
readystatechange(http, success, error)
})
}
const readystatechange = (ajax, success, error) => {
ajax.onreadystatechange = () => {
// http status
// ajax readyState
// 接口提供的 标识当前你访问的接口操作的 具体信息
if (ajax.readyState == 4) {
if (ajax.status == 200) {
NProgress.done();
let result = JSON.parse(ajax.responseText)
switch (result.status) {
case 200:
success(result.data)
break;
case 500:
alert(result.message)
break;
default:
break;
}
} else {
error(ajax)
console.error(ajax)
}
}
}
}
// 处理get请求参数并 拼接地址
const handleGetParams = (params) => {
let str = ""
for (const key in params.data) {
str += `&${key}=${params.data[key]}`
}
str = str.replace("&", "?")
return config.checkStage() + params.url + str
}
return { get, post }
}

View File

@@ -0,0 +1,22 @@
// 每一个页面都应该有一个init方法
// 用来做初始化
const init = async () => {
header(
"",
"热门",
)
footer()
getHotList()
}
const getHotList = async () => {
data = await hotList(
{ page: 1 }
);
item(".random ul", data.list);
}
init()

View File

@@ -0,0 +1,58 @@
let mySwiper = null
// 每一个页面都应该有一个init方法
// 用来做初始化
const init = async () => {
footer()
getTagRecommend()
getHomeBanner()
getHomeHot()
getHomeList()
}
const getHomeBanner = async () => {
innerMaps(
".swiper-wrapper",
await homeBanner(),
v => `<div class="swiper-slide">
<img src="${v.src}" alt="">
</div>`
)
initSwiper();
}
const getTagRecommend = async () => {
innerMaps(
".recommend-tag",
await tagRecommend(),
v => `
<li>
<a href="">
<div class="title">${v.short_title}</div>
<div class="desc">${v.title}</div>
</a>
</li>
`
)
}
const getHomeHot= async () => item(".roll ul",await homeHot())
const getHomeList = async () => item(".random ul", await homeList())
const initSwiper = () => {
mySwiper = new Swiper('.banner', {
loop: true, // 循环模式选项
// 如果需要分页器
pagination: {
el: '.swiper-pagination',
},
})
}
init()

View File

@@ -0,0 +1,95 @@
// 每一个页面都应该有一个init方法
// 用来做初始化
let infoData = {}
let likeData = JSON.parse(localStorage.getItem("like")) || []
const init = async () => {
header(
`<div class="flex ai-c">
<i class="iconfont icon-wujiaoxing "></i>
<i class="iconfont icon-fenxiang"></i>
</div>`,
)
getInfoList()
bindEvent()
}
const getInfoList = async () => {
infoData = await infoList({ id: query("id") })
$(".header_title").innerText = infoData.title
item(".recommend-model ul", infoData.recommend)
innerMaps(
".info .img_arr",
infoData.src_list,
(v, i) => `<a href="${v}" class="js-smartPhoto" data-id="${i}">
<img data-src="${v}" class="lazyload" data-sizes="auto" alt="">
</a>`
)
_(".img_arr img").click(v => {
new SmartPhoto(".js-smartPhoto", {
resizeStyle: 'fit'
});
});
}
const bindEvent = () => {
_(".all").click(v => {
$(".info").classList.replace("hidden", "show")
})
_(".icon-fenxiang").click(async v => {
await navigator.clipboard.writeText(stripIndents`
我发现一个好看的,快来看看: 《${infoData.title}
${location.href}
`);
alert("已粘贴,快分享给朋友吧")
})
// 在这判断 写真是否收藏
// foreach map filter
// 如果写真已经被收藏在本地,那么将图标改为收藏状态(实心)
likeData.filter(v => v.id == query("id") ? v : null).length != 0
? $(".icon-wujiaoxing").classList.add("icon-wujiaoxing1")
: null
_(".icon-wujiaoxing").click(async v => {
// $(".icon-wujiaoxing").classList.toggle("icon-wujiaoxing1")
// 取消收藏
if ($(".icon-wujiaoxing").classList.contains("icon-wujiaoxing1")) {
$(".icon-wujiaoxing").classList.remove("icon-wujiaoxing1")
likeData = likeData.filter((v,i) => {
if (v.id != query("id")) {
return v
}
})
localStorage.setItem("like", JSON.stringify(likeData))
// 收藏
} else {
likeData.push({
id: query("id"),
title: infoData.title,
thumbnail: infoData.src_list[0],
time: query("time"),
view: query("view")
})
localStorage.setItem("like", JSON.stringify(likeData))
$(".icon-wujiaoxing").classList.add("icon-wujiaoxing1")
}
})
}
init()

View File

@@ -0,0 +1,9 @@
// 每一个页面都应该有一个init方法
// 用来做初始化
const init = async () => {
footer()
}
init()

View File

@@ -0,0 +1,134 @@
let mySwiper = null;
let tagListData = [];
let tagIndex = 0;
const init = async () => {
header(
"",
"分类",
)
footer()
await getTagList()
initSwiper()
bindEvent()
}
const getTagList = async () => {
tagListData = await tagList()
console.log("tagListData: ", tagListData);
innerMaps(
".tabs_title",
tagListData,
(v, i) => `
<li class="${i == tagIndex ? 'active' : ''}">${v.title}</li>
`
)
innerMaps(
".tabs_content .swiper-wrapper",
tagListData,
v => `
<div class="swiper-slide recommend-model">
<ul class="list flex wrap p18 jc-sb"></ul>
</div>
`
);
await getTagInfo()
}
const getTagInfo = async () => {
let res = await tagInfo({
url: tagListData[tagIndex].url,
page: tagListData[tagIndex].page
})
tagListData[tagIndex].totalPage = res.totalPage
// tagListData[tagIndex].content = res.list
tagListData[tagIndex].content = [
...tagListData[tagIndex].content,
...res.list
]
// res.list.forEach(v => {
// tagListData[tagIndex].content.push(v)
// })
item(
_(".swiper-wrapper .swiper-slide ul")[tagIndex],
res.list
)
// 渲染页面
// item()
// 滚动加载更多数据....
console.log("getTagInfo: ", tagListData);
}
const initSwiper = async () => {
mySwiper = new Swiper('.tabs_content', {
on: {
slideChangeTransitionEnd: async function () {
tagIndex = this.activeIndex
changeLiActive(this.activeIndex)
if (tagListData[tagIndex].content.length == 0) {
await getTagInfo()
}
},
},
})
}
const bindEvent = async () => {
_(".tabs_title li").click((v, i) => {
mySwiper.slideTo(i)
})
// TODO 防抖 节流 优化这块代码
_(".swiper-slide").scroll(async v => {
//文档内容实际高度(包括超出视窗的溢出部分)
// ul 总高度
let ulHeight = v.children[0].clientHeight;
//滚动条滚动距离
// ul 在 swiper-slide 中的滚动距离
let ulScrollTop = v.scrollTop
//窗口可视范围高度
// swiper-slide 高度
let SwiperSlideHeight = v.clientHeight
// console.log("ulHeight: ", ulHeight);
// console.log("ulScrollTop: ", ulScrollTop);
// console.log("SwiperSlideHeight: ", SwiperSlideHeight);
// console.log("");
if (SwiperSlideHeight + ulScrollTop >= ulHeight) {
tagListData[tagIndex].page += 1
if (tagListData[tagIndex].page <= tagListData[tagIndex].totalPage) {
console.log("===加载更多内容……===");
await getTagInfo()
}
}
})
}
const changeLiActive = async (index) => {
_(".tabs_title li").forEach(v => v.classList.remove("active"))
_(".tabs_title li")[index].classList.add("active")
}
init()

View File

@@ -0,0 +1,38 @@
/**
*
* @param {*} data 是get请求的参数
* 由页面调用者传递过来给我
*/
const homeBanner = async (data = {}) => {
return await http().get({
url: config.urlList.homeBanner,
// data: data
data
})
}
const homeHot = async (data = {}) => {
let res = await http().get({
url: config.urlList.homeHot,
// data: data
data
})
res.forEach(v => v.view = v.view.replaceAll("W+", ""));
return res
}
const homeList = async (data = {}) => {
let res = await http().get({
url: config.urlList.homeList,
// data: data
data
});
res.forEach(v => v.view = v.view.replaceAll("W+", ""));
return res
}

View File

@@ -0,0 +1,11 @@
const hotList = async (data = {}) => {
let res = await http().get({
url: config.urlList.hotList,
// data: data
data
});
console.log(res)
res.list.forEach(v => v.view = v.view.replaceAll("W+", ""));
return res
}

View File

@@ -0,0 +1,7 @@
const infoList = async (data = {}) => {
return await http().get({
url: config.urlList.infoList,
// data: data
data
});
}

View File

@@ -0,0 +1,33 @@
const tagRecommend = async (data = {}) => {
let res = await http().get({
url: config.urlList.tagRecommend,
// data: data
data
});
res.forEach(v => v.short_title = v.title.substring(0,1));
return res
}
const tagList = async (data = {}) => {
let res = await http().get({
url: config.urlList.tagList,
// data: data
data
});
res.forEach(v => {
v.page = 1;
v.totalPage = 0;
v.content = [];
});
return res;
}
const tagInfo = async (data = {}) => {
return await http().get({
url: config.urlList.tagInfo,
// data: data
data
});
}

View File

@@ -0,0 +1,106 @@
const footer = () => {
let currentHref = location.href
let html = `
<ul class="footer fixed flex jc-sb ai-c border-box border-top">
${config.footerArr.maps((v, i) => {
return `<li class="${location.href.includes(v.href) ? 'active' : ''}">
<a href="${v.href}">
<i class="iconfont ${v.icon}"></i>
<div>${v.title}</div>
</a>
</li>`
})}
</ul>
`
$("body").insertAdjacentHTML("beforeend", html)
}
const header = (right, center = "", left = `<i class="iconfont icon-fanhui"></i>`) => {
let html = `
<div class="header fixed flex ai-c jc-sb p18 border-box border-bottom">
${left}
<div class="header_title ellipsis">${center}</div>
${right}
</div>
`
$("body").insertAdjacentHTML("afterbegin", html)
_(".header .icon-fanhui").click(v => {
history.back()
})
}
const item = (father, data) => {
(typeof father == "string" ? $(father) : father).insertAdjacentHTML("beforeend",data.maps(v => {
return `
<li>
<a href="./info.html?id=${v.id}&time=${v.time}&view=${v.view}">
<img src="${v.thumbnail}" alt="">
<div class="desc">
<div class="name ellipsis">${v.title}</div>
<div class="time flex ai-c jc-sb">
<div class="text">${v.time}</div>
<div class="view flex ai-c">
<i class="iconfont icon-liulan"></i>
<span>${v.view}W+</span>
</div>
</div>
</div>
</a>
</li>
`
}))
}
const query = name =>{
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return decodeURIComponent(r[2]); return null;
}
const stripIndents = (template, ...expressions) => {
let result = template.reduce((prev, next, i) => {
let expression = expressions[i - 1];
return prev + expression + next;
});
result = result.replace(/\n[^\S\n]*/g, '\n');
result = result.trim();
return result;
}
const innerMaps = (father, data, callback) => {
$(father).insertAdjacentHTML("afterbegin", data.maps((v,i) => {
return callback(v,i)
}))
}
const $ = className => {
return document.querySelector(className)
}
const _ = className => {
return document.querySelectorAll(className)
}
// prototype 原型
// js给我们提供的一个方法通过这个方法作为入口
// 我们可以直接对js进行修改
Array.prototype.maps = function (callback) {
let result = []
for (let i = 0; i < this.length; i++) {
result.push(callback(this[i], i, this))
}
return result.toString().replaceAll(",", "")
}
NodeList.prototype.click = function (callback) {
this.forEach((v,i) => v.onclick = () => callback(v,i))
}
NodeList.prototype.scroll = function (callback) {
this.forEach((v,i) => v.onscroll = () => callback(v,i))
}

View File

@@ -0,0 +1,10 @@
(function (w, d) {
function setSize() {
var screenWidth = d.documentElement.clientWidth;
var currentFontSize = screenWidth * 100 / 750;
d.documentElement.style.fontSize = currentFontSize + 'px';
}
w.addEventListener('resize', setSize);
w.addEventListener('pageShow', setSize)
w.addEventListener('DOMContentLoaded', setSize)
})(window, document)

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>热门</title>
<script src="../js/utils/rem.js"></script>
<link rel="stylesheet" href="https://unpkg.com/nprogress@0.2.0/nprogress.css">
<link rel="stylesheet" href="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4738996_qxm9myzsi3m.css">
<link rel="stylesheet" href="../css/clear.css">
<link rel="stylesheet" href="../css/color.css">
<link rel="stylesheet" href="../css/public.css">
<link rel="stylesheet" href="../css/global.css">
<link rel="stylesheet" href="../css/index.css">
</head>
<body>
<div class="content">
<div class="recommend-model random">
<ul class="list flex wrap p18 jc-sb"></ul>
</div>
</div>
</body>
<script src="https://unpkg.com/nprogress@0.2.0/nprogress.js"></script>
<script src="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.js"> </script>
<script src="../js/utils/index.js"></script>
<script src="../js/config/index.js"></script>
<script src="../js/http/index.js"></script>
<script src="../js/serve/home.js"></script>
<script src="../js/serve/tag.js"></script>
<script src="../js/serve/hot.js"></script>
<script src="../js/page/hot.js"></script>
</html>

View File

@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
<script src="../js/utils/rem.js"></script>
<link rel="stylesheet" href="https://unpkg.com/nprogress@0.2.0/nprogress.css">
<link rel="stylesheet" href="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4738996_qxm9myzsi3m.css">
<link rel="stylesheet" href="../css/clear.css">
<link rel="stylesheet" href="../css/color.css">
<link rel="stylesheet" href="../css/public.css">
<link rel="stylesheet" href="../css/global.css">
<link rel="stylesheet" href="../css/index.css">
</head>
<body>
<div class="header fixed flex ai-c jc-c">
<a class="search flex-block ai-c border-box" href="./search.html">
<i class="iconfont icon-sousuo-m"></i>
<div>开启精彩搜索..</div>
</a>
</div>
<div class="content">
<div class="swiper banner">
<div class="swiper-wrapper"></div>
<!-- 如果需要分页器 -->
<div class="swiper-pagination"></div>
</div>
<ul class="recommend-tag flex jc-sb"></ul>
<!-- 横向滑动 -->
<div class="recommend-model roll">
<div class="title p18 flex ai-c">推荐写真</div>
<ul class="list flex p18 jc-sb"></ul>
</div>
<div class="recommend-model random">
<!-- <div class="title p18 flex ai-c">随机写真</div> -->
<ul class="list flex wrap p18 jc-sb"></ul>
</div>
</div>
</body>
<script src="https://unpkg.com/nprogress@0.2.0/nprogress.js"></script>
<script src="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.js"> </script>
<script src="../js/utils/index.js"></script>
<script src="../js/config/index.js"></script>
<script src="../js/http/index.js"></script>
<script src="../js/serve/home.js"></script>
<script src="../js/serve/tag.js"></script>
<script src="../js/page/index.js"></script>
<script>
// let c = [1, 2, 3, 4, 5]
// Array.prototype.maps = function (callback) {
// let result = []
// for (let i = 0; i < this.length; i++) {
// result.push(callback(this[i], i, this))
// }
// return result.toString().replaceAll(",", "")
// }
// let d = c.maps(v => {
// return `<div>${v}</div>`
// })
// console.log(d);
</script>
</html>

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>详情页</title>
<script src="../js/utils/rem.js"></script>
<link rel="stylesheet" href="https://unpkg.com/smartphoto@1.1.0/css/smartphoto.min.css">
<link rel="stylesheet" href="https://unpkg.com/nprogress@0.2.0/nprogress.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4738996_qxm9myzsi3m.css">
<link rel="stylesheet" href="../css/clear.css">
<link rel="stylesheet" href="../css/color.css">
<link rel="stylesheet" href="../css/public.css">
<link rel="stylesheet" href="../css/global.css">
<link rel="stylesheet" href="../css/info.css">
</head>
<body>
<div class="content">
<div class="info relative hidden">
<div class="img_arr" data-expand="-100">
</div>
<div class="all absolute flex jc-c ai-e border-box">
<span>展开更多</span>
<i class="iconfont icon-zhankai-copy"></i>
</div>
</div>
<div class="recommend-model">
<div class="title p18 flex ai-c">推荐写真</div>
<ul class="list flex wrap p18 jc-sb"></ul>
</div>
</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/lazysizes/5.3.2/lazysizes.min.js"></script>
<script src="https://unpkg.com/nprogress@0.2.0/nprogress.js"></script>
<script src="https://unpkg.com/smartphoto@1.1.0/js/smartphoto.min.js"></script>
<script src="../js/utils/index.js"></script>
<script src="../js/config/index.js"></script>
<script src="../js/http/index.js"></script>
<script src="../js/serve/info.js"></script>
<script src="../js/page/info.js"></script>
</html>

View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的</title>
<script src="../js/utils/rem.js"></script>
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4738996_qxm9myzsi3m.css">
<link rel="stylesheet" href="../css/clear.css">
<link rel="stylesheet" href="../css/color.css">
<link rel="stylesheet" href="../css/public.css">
<link rel="stylesheet" href="../css/global.css">
<link rel="stylesheet" href="../css/me.css">
</head>
<body>
</body>
<script src="../js/utils/index.js"></script>
<script src="../js/config/index.js"></script>
<script src="../js/http/index.js"></script>
<script src="../js/serve/home.js"></script>
<script src="../js/page/me.js"></script>
</html>

View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分类</title>
<script src="../js/utils/rem.js"></script>
<link rel="stylesheet" href="https://unpkg.com/nprogress@0.2.0/nprogress.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4738996_qxm9myzsi3m.css">
<link rel="stylesheet" href="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.css">
<link rel="stylesheet" href="../css/clear.css">
<link rel="stylesheet" href="../css/color.css">
<link rel="stylesheet" href="../css/public.css">
<link rel="stylesheet" href="../css/global.css">
<link rel="stylesheet" href="../css/type.css">
</head>
<body>
<div class="content">
<ul class="tabs_title flex p18 x-scroll ai-c fixed"></ul>
<div class="swiper tabs_content">
<div class="swiper-wrapper"></div>
</div>
</div>
</body>
<script src="https://unpkg.com/nprogress@0.2.0/nprogress.js"></script>
<script src="https://unpkg.com/swiper@8.4.7/swiper-bundle.min.js"> </script>
<script src="../js/utils/index.js"></script>
<script src="../js/config/index.js"></script>
<script src="../js/http/index.js"></script>
<script src="../js/serve/tag.js"></script>
<script src="../js/page/type.js"></script>
</html>

Binary file not shown.

View File

@@ -0,0 +1,26 @@
cookies:
把用户登录成功的状态放在请求头中
每次访问网址的时候后端会从请求头中拿到cookies
然后判断用户是否登录成功
缺点:
cookie可能被禁用
cookie与浏览器相关不能互相访问
cookie可能被用户删除
cookie安全性不够高
cookie存储空间很小(只有410KB左右)
session:
生命周期是仅在当前浏览器窗口关闭前有效,不能持久保持。
在整个浏览器未关闭前其数据一直都是存在的。存储大小一般为5M
localStorage:
http 协议 它是无状态
状态(是否登录)
http
http