app.vue页面

初始化数据,通过调用vuex mutation里定义的方法 调用保存到localstorage中的书架信息、搜索历史记录、字体大小和皮肤

并把这些数据保存的vuex state中

1.书架页 Myshelf

url:http://localhost:8080/myshelf

myshelf页面有 header、shelf-list、tabbar组件

重点:

1.从vuex state中获取已经保存的书架信息

2.处理时间,返回距离现在几小时的格式

<span class="time red">{{ book.updated | time}}</span>

import moment from 'moment';

    filters: {
time(updated) {
moment.locale('zh-cn');
return moment(updated).fromNow();
}
},

3.删除书架书籍提示是否确认删除

调用mint-ui的messagebox,MessageBox.confirm() 返回的是一个promise对象,点击确认可被then捕获,点击取消可被catch捕获

import { MessageBox } from 'mint-ui';

    showDialog(book_id){
MessageBox.confirm('确定要从书架中删除?', '温馨提示').then(action => { 
 if (action == 'confirm') {     //确认的回调
  console.log(1); 
this.deleteFromShelft(book_id)
 }
 }).catch(err => { 
  if (err == 'cancel') {     //取消的回调
  console.log('取消');
  } 
})
}

调用写在mutation中的deleteFromShelft,通过filter筛选出对象,再重新保存到localstrage覆盖之前的保存信息

  // 删除特定书从书架
deleteFromShelft(state,book_id){
state.shelf_book_list = state.shelf_book_list.filter(value => {
return !book_id.includes(value.id);
});
// 重现覆盖localstorage
setStore('SHEFL_BOOK_LIST', state.shelf_book_list);
},
// 删除全部书从书架
deleteAllShelft(state){
state.shelf_book_list.clear();
removeStore('SHEFL_BOOK_LIST')
},

补充:数组includes用法

语法:arr.includes(searchElement)
   arr.includes(searchElement, fromIndex)

includes() 方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。

2.主页面home

吸顶效果

    <div class="tabs-warp" :class="searchBarFixed == true ? 'isFixed' :''">
<div ref="tabsContent" class="tabs-content">
<!-- 导航 -->
</div>
<div v-if="searchBarFixed" class="replace-tab"></div>

定义函数 当滑动距离超过tab栏到顶部距离的时候,应用isFixed样式。

    handleScroll () {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
if(this.offsetTop==0){
this.offsetTop=document.querySelector('.tabs-warp').offsetTop-document.querySelector('.header').offsetHeight
}
if (scrollTop > this.offsetTop) {
this.searchBarFixed = true
} else {
this.searchBarFixed = false
}
},

在mounted阶段,监听滚动,当滚动的时候实现上面的函数

  mounted(){
window.addEventListener('scroll', this.handleScroll)
},

当离开组件的时候需要移除

  destroyed () {
window.removeEventListener('scroll', this.handleScroll)
},

滑动内容带动tab栏滑动

    <div class="tabs-warp" :class="searchBarFixed == true ? 'isFixed' :''">
<div ref="tabsContent" class="tabs-content">
<div style="display: inline-block"> <!--PC端运行,加上这个div可修复tab-bar错位的问题 -->
<ul class="tabs" ref="tabs">
<li class="tab" v-for="(tab,i) in tabs" :class="{active: i===curIndex}" :key="i" @click="changeTab(i)">{{tab.name}}</li>
</ul>
<div class="tab-bar" :style="{left: barLeft}"></div>
</div>
</div>
</div>
<!-- -->
<div v-if="searchBarFixed" class="replace-tab"></div>
<!--轮播-->
<swiper ref="mySwiper" :options="swiperOption">
<swiper-slide>
<!-- 精选 -->
<div v-for="(feature_item,index) in feature_channel" :key="index">
<v-home-list :channel="feature_item"></v-home-list>
</div>
</swiper-slide>
<swiper-slide>
<!-- 男频 -->
<div v-for="(male_item,index) in male_channel" :key="index">
<v-home-list :channel="male_item"></v-home-list>
</div>
</swiper-slide>
<swiper-slide>
<!-- 女频 -->
<div v-for="(female_item,index) in female_channel" :key="index">
<v-home-list :channel="female_item"></v-home-list>
</div>
</swiper-slide>
<swiper-slide>
<!-- 限免 -->
<div v-for="(free_item,index) in free_channel" :key="index">
<v-home-list :channel="free_item"></v-home-list>
</div>
</swiper-slide>
<swiper-slide>
<!-- 出版 -->
<div v-for="(publish_item,index) in publish_channel" :key="index">
<v-home-list :channel="publish_item"></v-home-list>
</div>
</swiper-slide>
</swiper>

引入插件

import { swiper, swiperSlide } from 'vue-awesome-swiper'

设置swiper

  data () {
return {
curIndex: 0, // 当前tab的下标
tabScrollLeft: 0, // 菜单滚动条的位置
swiperOption: { // 轮播配置
on: {
transitionEnd: () => {
this.changeTab(this.swiper.activeIndex)
}
}
},
isMounted:false,
searchBarFixed:false,
offsetTop:0, //吸顶
}
},

监听轮播

  computed: {
swiper () { // 轮播对象
return this.$refs.mySwiper.swiper
},
barLeft () { // 红线的位置
// 需要等dom加载完才能获取到dom
if(this.isMounted){
var tabWidth=document.getElementsByClassName('tab')[0].offsetWidth
var barWidth=document.getElementsByClassName('tab-bar')[0].offsetWidth
return (tabWidth * this.curIndex + (tabWidth - barWidth) / 2) + 'px'
}
}
},

当轮播切换的时候执行changeTab,tabIndex为轮播的索引

  methods: {
// 切换菜单
changeTab (tabIndex) {
if (this.curIndex === tabIndex) return; // 避免重复调用
let curTab = this.tabs[this.curIndex];// 当前列表
let newTab = this.tabs[tabIndex];// 新转换的列表
this.curIndex = tabIndex; // 切换菜单
curTab.mescroll
this.swiper.slideTo(tabIndex);
let tabsContent = this.$refs.tabsContent;
let tabDom = tabsContent.getElementsByClassName('tab')[tabIndex];
let star = tabsContent.scrollLeft;// 当前位置
let end = tabDom.offsetLeft + tabDom.clientWidth / 2 - document.body.clientWidth / 2; // 居中
this.tabScrollLeft = end;
tabsContent.scrollLeft = end;
},
},
}

3.分类页面

1.排行榜页面rank.vue

url:http://localhost:8080/rank

rank.vue里只有通用booklist组件

1.create

请求数据,并保持数据到data,并默认加载全部

2.watch

监听rank.id,rank.id对应左边标签,当rank.id改变的时候重新请求数据

3.组件

父组件通过prop 传递bookList数据给booklist组件

<book-list :book-list="bookList" v-if="bookList.length > 0"></book-list>

补充:图片资源的路径和数据请求的路径不同,需要区分

通用组件

1.booklist组件

1.router-link跳转
<router-link :to="{ name: 'book', params: {id: book._id} }">
通过命名路由跳转到子组件

2.computed 计算处理data

3.filter用于处理data数据的返回特定格式

   如 filters: {
        time(update) {
            return moment(update).format('YYYY-MM-DD');
        }
    },

2.图书详情页book.vue

url:http://localhost:8080/book/55eef8b27445ad27755670b9

book里有bookinfo review recommend bookbar

1.create

判断该书是否保存在书架

1.如果当前书籍已存在书架中,则书架中的书籍设置为当前书籍

2.如果不在 调用vuex中的mutation 保存自定义的book对象,并保持 this.$route.params.id

            this.SET_CUR_BOOK({
id: this.$route.params.id, //书籍id
title: '', //书名
cover: '', //封面
author: '', //作者
lastChapter: '', //已更新的最新章节
updated: '', //更新时间
readChapter: '', //已读章节
isInShelf: false, //是否已在书架中,false:不在,true:在
sort: false //目录顺序,false:正序, true:倒序
});

2.组件

1.bookinfo组件

create请求数据    调用vuex 参数为父级保存的 id: this.$route.params.id

2.revew组件

。。。

3.阅读页面 read.vue

1.create

保存id this.bookId = this.$route.params.id;
判断是否从图书详情页点击目录过来,是则显示章节目录,否默认显示阅读页面
请求章节列表数据 
 
2.method
点击下一章节
选择章节
 
3.beforeRouteLeave

路由退出
判断是否添加到书架
    beforeRouteLeave(to, from, next) {
//当书籍不在书籍并且不是从目录过来
if (!this.curBook.isInShelf && !this.isFromMenu) {
//显示提示框
this.showDialog = true;
//调用子组件dialog的confirm方法
this.$refs.dialog.confirm().then(() => {
this.showDialog = false;
let book = this.curBook;
//添加到书架保存
book.isInShelf = true;
this.SET_CUR_BOOK(book);
this.ADD_TO_SHELF(book);
next();
}).catch(() => {
this.showDialog = false;
next();
})
} else {
next()
}
}
 分割文章
"诺德王国一年只有三个月的时间会是温暖的,别的时间这里似乎总是被风雪和寒冷笼罩,这里的冬天是如此地寒冷以至于晨曦之神能带给这里晨光却无法带来温暖,农业女神的信徒们总是努力地想方设法在那些肥沃可是终年寒冷的土地上播种耐寒的作物,如小麦、大麦、油菜等,一年一熟的农业勉强供给着这个国家的口粮所需。↵↵  夜晚,位于诺德领北方的乌兰镇静悄悄,又是一年的隆冬时节,天空一如既往地飘起了鹅毛大雪,落在家家户户的屋顶,就连道路上也落得厚厚一层积雪,小镇的空气静谧无声,房屋的烟囱冒出浓浓黑烟,天上的星辰带给地面微弱的星光,大雪却把一切掩埋。↵↵  这个季节,太阳下山的时间很早,天黑之后,快一分回到城镇就多一分安全,慢一分回到城镇就多一分危险,日落之后的野外什么都有,强盗、野兽人、不时来劫掠的北方蛮族、甚至是可怕的绿皮或者亡灵都时有出没,小镇的居民们基本不会选择在这个时候外出,只有家里的房门和温暖的壁炉能带给他们安全感。↵↵  一个银装素裹的世界,除了偶尔经过的巡逻卫兵,小镇内一片黑暗,像一个死城,隆冬的寒风不断地呼啸而过,雪花在天际间飘洒,在这个一年最寒冷的季节,小镇的居民们都只能躲在自己的家里,盼望着能够早日等来开春的一刻。↵↵  一支黑色的皮靴踩在城门口的台阶上"

1.str = str.replace(/↵/g,"<br/>");
2.str=str.replace(/\n/g,"<br/>")
3.array=array.split('\n')
具体哪一种需要看编辑器的换行符,不一定生效
 

功能

1.页面弹出设置栏效果

    <div class="config">
<div :class="['config-top','bg-black', { 'config-enter': show_config }]">顶部栏</div>
<div :class="['config-right','bg-black', { 'config-enter': show_config }]">加入书架</div>
<div :class="['config-bottom','bg-black', { 'config-enter': show_config }]">
<div class="config-bootom-item">目录</div>
<div class="config-bootom-item" @click="showNightMode()">夜间模式</div>
<div class="config-bootom-item">设置</div>
</div>
</div>
showConfig(){
 if(!this.show_config){
   this.show_config=true
 }else{
  this.show_config=false
 }
},
  .bg-black{
color: #fff;
background-color: rgba(0, 0, 0, 0.9);
transition: transform 0.15s ease 0s;
text-align: center;
}
.config-top{
position: fixed;
width: 100%;
height: .8rem;
top:0;
left:0;
transform: translateY(-100%);
}
.config-right{
position: fixed;
right: 0;
top:20%;
width: 1.6rem;
height: .6rem;
line-height: .6rem;
transform: translateX(100%);
border-top-left-radius: .3rem;
border-bottom-left-radius: .3rem;
}
.config-bottom{
position: fixed;
display: flex;
width: 100%;
height: 1rem;
bottom: 0;
left: 0;
justify-content: space-between;
transform: translateY(100%);
&>.config-bootom-item{
flex:0 0 33.3%;
}
}
.config-enter{
transform: translate(0%, 0%);
}

首页设置transform偏移到屏幕外,并设置transition效果

2.页面只有点击中心区域弹出设置栏,点击其他区域不弹出

<div class="read-touch" @click="showConfig()"></div>
.read-touch{
position: fixed;
width: 60%;
height: 40%;
top: 30%;
left: 20%;
z-index: 1000;
}

3.目录排序,正序和倒序

目录是一个数组,可以通过数组自带reverse()来排序

4.点击目录弹出目录

重点:Read.vue包含两个组件  1.ReadContent书页面   和    2.Chapter目录页面

1.点击弹出目录的按钮在ReadContent组件,2目录显示在Chapter组件。

解决方法:通过$emit 将ReadContent(子组件)的信息传到Read.vue(父组件),再由父组件prop传递到 Chapter(子组件)

Read.vue组件

<template>
<section class="read">
<v-read-content :read-content="read_content" @show-chapter="showChapter()"></v-read-content>
<v-chapter :chapter-name="chapter_name" :chapter-show="chapter_show" @select-chapter="selectChapterData"></v-chapter>
</section>
</template> <script>
import http from '../http/api'
import {mapState,mapMutations} from 'vuex';
import ReadCotent from '../components/common/ReadContent'
import Chapter from '../components/common/Chapter'
export default {
name:'read',
components:{
'v-read-content':ReadCotent,
'v-chapter':Chapter
},
data(){
return{
book_id:'',
chapter_name:[],
chapter_show:false,
read_content:[],
read_index:0
}
},
watch:{
// 监听章节和阅读到第几章变化
chapter_name(){
this.getChapterData(this.chapter_name[this.read_index].id)
},
read_index(){ }
},
methods:{
// 获取所有章节名
getChapterName(book_id){
http.getChapters(book_id)
.then(data => {
this.chapter_name=data
})
},
// 获取特定章节内容
getChapterData(chapter_id){
http.getChapterContent(chapter_id)
.then(data => {
this.read_content.push({
content_title: data.title,
content_list: data.isVip ? ['vip章节,请到正版网站阅读'] : data.cpContent.split('\n') //换行符分割文章
});
var aa=data.cpContent.split('\n')
})
},
// ReadContent组件传出的是否显示章节
showChapter(){
this.chapter_show=true
},
selectChapterData(chapter_id){
// 先清空原有书籍
// this.readContent.splice(0, this.readContent.length);
this.read_content=[]
this.getChapterData(chapter_id)
this.chapter_show=false
}
},
created(){
this.book_id=this.$route.params.id;
this.getChapterName(this.book_id)
}
}
</script>

ReadContent.vue组件

<template>
<section :class="['read-content',skin_color,{'night-color':night_mode}]" v-if="readContent.length>0" >
<div class="config">
<div :class="['config-top','bg-black', { 'config-enter': show_config }]">顶部栏</div>
<div :class="['config-right','bg-black', { 'config-enter': show_config }]">加入书架</div>
<div :class="['config-bottom','bg-black', { 'config-enter': show_config }]">
<div class="config-bootom-item" @click="showChapter()">目录</div>
<div class="config-bootom-item" @click="showNightMode()">夜间模式</div>
<div class="config-bootom-item" @click="showConfigPop()">设置</div>
</div>
<!-- 设置字体颜色弹出层 -->
<div class='config-bootom-pop' v-show="show_config_pop">
<ul class="config-skin-color">
<li class="color-item" v-for="(skin,index) in skin_list" :key="index">
<span :class="['color-round-btn',skin,{'skin_color_active':skin==skin_color}]" @click="changeSkinColor(skin)"></span>
</li>
</ul>
<div class="config-control-fontsize">
<button @click="changeFontSize(false)">A-</button>
<button @click="changeFontSize(true)">A+</button>
</div>
</div>
</div> <div class="read-tag">民国谍影</div>
<h4 class="read-title">{{readContent[0].content_title}}</h4>
<div class="read-touch" @click="showConfig()"></div>
<ul >
<li :style="{ fontSize: font_size + 'px' }" v-for="(item,index) in readContent[0].content_list" :key="index">
{{item}}
</li>
</ul> </section>
</template> <script>
export default {
name:'readcontent',
props:{
readContent:Array
},
data(){
return{
show_config:false, //设置弹出层
show_config_pop:false, //设置皮肤字体弹出层
skin_color:'', //皮肤颜色
night_mode:false, //夜晚模式
skin_list:['skin-default', 'skin-blue', 'skin-green', 'skin-pink', 'skin-dark', 'skin-light'],
// skin_color_active:'',
font_size:14 }
},
methods:{
// 显示设置弹出层
showConfig(){
if(!this.show_config){
this.show_config=true
}else{
this.show_config=false
this.show_config_pop=false
}
},
// 夜间模式
showNightMode(){
this.skin_color=false
if(!this.night_mode){
this.night_mode=true
}else{
this.night_mode=false
}
},
// 显示弹出层皮肤和字体大小
showConfigPop(){
this.show_config_pop=true
},
changeSkinColor(skin){
this.night_mode=false
this.skin_color=skin
},
changeFontSize(isAdd){
console.log(this.font_size)
// if ((this.font_size >= 30 && isAdd) || (this.font_size <= 10 && !isAdd)) {
// return;
// }
let size = this.font_size;
isAdd ? size++ : size--
this.font_size=size
// this.SET_FONT_SIZE(size);
},
// 显示章节 $emit触发父组件
showChapter(){
// this.show_config=false
this.$emit('show-chapter'); }
} }
</script> <style lang="scss" scoped>
// 皮肤颜色和夜晚模式
.night-color{
color: rgba(255, 255, 255, .5);
background-color: #1a1a1a;
}
.skin-default {
background-color: #c4b395;
} .skin-blue {
background-color: #c3d4e6;
} .skin-green {
background-color: #c8e8c8;
} .skin-pink {
background-color: #F8C9C9;
} .skin-dark {
background-color: #3E4349;
} .skin-light {
background-color: #f6f7f9;
} .read-content{
padding:0 .2rem;
// 设置
.bg-black{
color: #fff;
background-color: #13120F;
transition: transform 0.15s ease 0s;
text-align: center;
}
.config-top{
position: fixed;
width: 100%;
height: .8rem;
top:0;
left:0;
transform: translateY(-100%);
}
}
</style>

Chapter.vue组件

<template>
<section :class="['chapter',{'chapter-show':chapterShow}]">
<div class="chapter-title">返回</div>
<div class="chapter-head">
<span class="chapter-total">共{{chapterName.length}}章</span>
<span class="chapter-sort" @click="chapterSort()">
<span v-if="sort">倒序</span>
<span v-else>正序</span>
</span>
</div>
<div class="chapter-list-section">
<div class="chapter-top">正文卷</div>
<ul class="chapter-list">
<li class="chapter-list-item" v-for=" chapter in chapterName" :key="chapter.id" @click="selectChapter(chapter.id)">
<span>{{chapter.title}}</span>
<span v-if="chapter.isVip">vip</span>
</li>
</ul>
</div>
</section>
</template> <script>
export default {
name:'chapter',
props: {
chapterName: Array,
chapterShow:Boolean
},
data(){
return{
sort:true
}
},
methods:{
// 排序
chapterSort(){
this.sort=!this.sort
this.chapterName.reverse(); //数组reverse()
},
// 选择章节
selectChapter(chapter_id){
this.$emit('select-chapter', chapter_id);
}
}
}
</script> <style lang="scss" scoped>
.chapter-title{
height: .8rem;
} .chapter-show{
transform: translateX(0) !important;
}
.chapter{
position: fixed;
top:0;
left:0;
bottom:0;
right:0;
overflow: hidden;
z-index: 9999;
background-color: #fff;
transform: translateX(-100%);
transition: transform .15s; } </style>

vue 追书神器的更多相关文章

  1. vue仿追书神器,vue小说项目源码

    vue-reader 一点阅读器!API源自追书神器,免费使用!目前已初步开发完成! Github项目地址:https://github.com/AntonySufer/vue-readle 欢迎is ...

  2. 基于vue-cli3和追书神器制作的移动端小说阅读网站,附接口和源码

    项目简介 基于node express+mysql+vue-cli3和追书神器接口制作的移动端小说阅读网站,**仅供参考学习!不用于任何商业用途!** 闲暇时间用vue练练手,就想写个小说网站来看看, ...

  3. React+Redux实现追书神器网页版

    引言 由于现在做的react-native项目没有使用到redux等框架,写了一段时间想深入学习react,有个想法想做个demo练手下,那时候其实还没想好要做哪一个类型的,也看了些动漫的,小说阅读, ...

  4. 追书神器API

    由于自己喜欢看小说,有的时候不方便手机看的时候希望在电脑上面看,但很多网站有广告啊,于是封装了套手机版的追书神器API 目前只做了搜索 详情 书评 换源 正文 调用方式: //搜索小说 var sea ...

  5. Vue小说阅读器(仿追书神器)

    一个vue阅读器项目,目前已升级到2.0,阅读器支持横向分页并滑动翻页(没有动画,需要动画的可以自己设置,增加transitionDuration即可) 技术栈 vue全家桶+mint-ui gith ...

  6. 通过Charles获取看书神器API

    Charles Charles是一个可以做HTTP代理/ HTTP监视器/反向代理的软件,使开发人员能够查看其机器和Internet之间的所有HTTP和SSL / HTTPS流量.包括请求,响应和HT ...

  7. Vue开发调试神器 vue-devtools

    Vue开发调试神器: vue-devtools 1. 下载Chrome扩展插件GitHub下载地址: https://github.com/vuejs/vue-devtools 建议使用npm淘宝镜像 ...

  8. svn 追责神器 blame vscode - SVN Gutter

    svn 追责神器 blame vscode - SVN Gutter

  9. vue 代码调试神器

    一.序 工欲善其事,必先利其器.作为一名资深程序员,相信必有一款调试神器相伴左右,帮助你快速发现问题,解决问题.作为前端开发,我还很年轻,也喜欢去捣鼓一些东西,借着文章的标题,先提一个问题:大家目前是 ...

随机推荐

  1. MySQL教程之concat以及group_concat的用法

    本文中使用的例子均在下面的数据库表tt2下执行: 一.concat()函数 1.功能:将多个字符串连接成一个字符串. 2.语法:concat(str1, str2,...) 返回结果为连接参数产生的字 ...

  2. .NET WebAPI中使用Session使用

    问题及其解决方案: 今天做项目的时候因为需要编写一个短信验证码的接口我需要在我的后台.net webapi中存入我随机生成的短信验证码方便与前端传递过来的数据对比,所以决定使用session做缓存.但 ...

  3. PHP全栈学习笔记7

    图形图像处理技术,gd库的强大支持,PHP的图像可以是PHP的强项,PHP图形化类库,jpgraph是一款非常好用的强大的图形处理工具. 在PHP中加载GD库 gd官方网址下载: http://www ...

  4. 第3章 简单的C程序设计——顺序程序设计

    3.1 顺序程序设计举例 例:有人用温度计测量出用华氏法表示的温度(如64F),今要求把它转换为一摄氏法表示的温度(如17.8C) 解题思路:问题的关键在于找到两者的转换公式.根据物理学知识,公式为c ...

  5. 从壹开始微服务 [ DDD ] 之六 ║聚合 与 聚合根 (下)

    前言 哈喽大家周二好,上次咱们说到了实体与值对象的简单知识,相信大家也是稍微有些了解,其实实体咱们平时用的很多了,基本可以和数据库表进行联系,只不过值对象可能不是很熟悉,值对象简单来说就是在DDD领域 ...

  6. 机器学习算法GBDT的面试要点总结-上篇

    1.简介 gbdt全称梯度下降树,在传统机器学习算法里面是对真实分布拟合的最好的几种算法之一,在前几年深度学习还没有大行其道之前,gbdt在各种竞赛是大放异彩.原因大概有几个,一是效果确实挺不错.二是 ...

  7. python接口自动化(一)--什么是接口、接口优势、类型(详解)

    简介 经常听别人说接口测试,接口测试自动化,但是你对接口,有多少了解和认识,知道什么是接口吗?它是用来做什么的,测试时候要注意什么?坦白的说,笔者之前也不是很清楚.接下来先看一下接口的定义. 定义 接 ...

  8. Python爬虫入门教程 42-100 爬取儿歌多多APP数据-手机APP爬虫部分

    1. 儿歌多多APP简单分析 今天是手机APP数据爬取的第一篇案例博客,我找到了一个儿歌多多APP,没有加固,没有加壳,没有加密参数,对新手来说,比较友好,咱就拿它练练手,熟悉一下Fiddler和夜神 ...

  9. 总结http get和post的区别

    这个问题几乎面试的时候都会问到,是一个老生常谈的话题,然而随着不断的学习,对于以前的认识有很多误区,所以还是需要不断地总结的,学而时习之,不亦说乎. 什么是http? get.post常见的区别 ge ...

  10. 图像检索(5):基于OpenCV实现小型的图像数据库检索

    本文对前面的几篇文章进行个总结,实现一个小型的图像检索应用. 一个小型的图像检索应用可以分为两部分: train,构建图像集的特征数据库. retrieval,检索,给定图像,从图像库中返回最类似的图 ...