wiki viewer 仿版

参考:https://www.jianshu.com/p/d48ae4ca707e

项目简介

根据用户输入的文本检索维基百科的条目,显示前若干条结果,结果包含词条标题和内容摘要。

技术点

  • 利用wikipedia的API检索维基百科数据库,
    API文档地址是http://www.mediawiki.org/wiki/API:Main_page
    API在线实验地址:https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=jsonfm
    获取随机维基百科条目方法:http://en.wikipedia.org/wiki/Special:Random
    当时学习api的时候迷了好久,主要不知道该用什么参数才能获得和demo一样的结果,结果网上搜到一篇demo,关键点是list=search&srsearch=xxx
  • 搜索框动画
    用户界面在一开始,输入框是一个形似放大镜的图标,点击该图标,放大镜手柄逐渐缩短到0,图标成为一个圆,然后这个圆向两边分开,拉出一个输入框,输入框自动获取焦点,接着输入框尾端两条斜线段从右上角和右下角飞入,形成一个关闭的叉,点击该叉,动画逆向运行一遍,搜索框又还原为一个搜索图标。
    实现该动画的过程主要采用了以下技术:
    • 搜索图标手柄:用一个高度很小的div,对搜索框(包围块)绝对定位,利用css3旋转,让其成为一条斜线,作为搜索图标的手柄。修改div的宽度就可以修改手柄的长度。难点:由于css3旋转是相对div中心的,修改了div的长度以后,div的中心位置变了,旋转以后和之前的位置平行却不共线,达不到效果,为此还需要在div相对定位以后利用css3位移变换transform: translate(-50%,-50%) rotate(45deg);让不论div长度多少,div的中心都固定在一个位置。这样以后,缩短div时会向div中心收缩,那么这个中心放在哪儿呢?搜索图标圆的边缘上。此时div有一部分会显示在搜索图标圆内部,为解决这个问题,让div的z-index设置为-1,并给搜索图标圆(实际是搜索框包围块)加上和页面相同的背景,折叠掉div手柄在圆内的部分。
    • 搜索框的关闭叉:和搜索图标手柄类似,不同的动画过程中修改的css属性是其绝对定位位置。
    • 实现动画的js:在搜索框包含块上监听点击事件,根据点击事件目标和当前搜索框状态(我在搜索框关闭完全以后给其加collaspsedç±»)确定执行什么动画;各个动画的顺序执行:利用jquery的animate()方法回调函数。
  • 内容显示
    一开始我在html中写了12个用于填充结果内容的div>a>(h3+p),在分享项目时,伙伴们给的意见是动态生成dom,对此做了相应修改。

index.pug

<!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 维基百科搜索页面
        link(href="../css/style.css", rel="stylesheet")

    body
        section#search
            div
                a(href="http://zh.wikipedia.org/wiki/Special:Random" target="_blank")
                    button.button 点击出现随机词条
            form 
                .input-box-wrap
                    .input-box.collpased
                        input(type="text")
                        .shrink
                        .close.down
                        .close.up
                    .tail
                p 点击图标搜索
        section#result
        script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js")
        script(src="../js/index.js")

index.html

<!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>维基百科搜索页面</title>
    <link href="../css/style.css" rel="stylesheet"/>
  </head>
  <body>
    <section id="search">
      <div><a href="http://zh.wikipedia.org/wiki/Special:Random" target="_blank">
          <button class="button">点击出现随机词条</button></a></div>
      <form> 
        <div class="input-box-wrap">
          <div class="input-box collpased">
            <input type="text"/>
            <div class="shrink"></div>
            <div class="close down"></div>
            <div class="close up"></div>
          </div>
          <div class="tail"></div>
        </div>
        <p>点击图标搜索</p>
      </form>
    </section>
    <section id="result"></section>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="../js/index.js"></script>
  </body>
</html>

style.scss

//colors
$blue: #2E94B9;
$lightyellow: #FFFDC0;
$red: #D25565;
$orange: #F0B775;

/*基本与全局样式*/
body{
    background-color: $blue;
    font-size: 18px;
    color: white;
    width: 80%;
    margin: 10px auto;
}
ul, li, input, button, h1, h2, h3{
    margin: 0;
    padding: 0;
}
input, button{
    border-width: 0;
    background-color: transparent;
    color: $lightyellow;
    outline: none;
}
h1, h2, h3{
    margin-bottom: 16px;
}
a{
    text-decoration: none;
    color: black;
}
.off{
    display: none;
}
/*============
搜索栏部分
==============*/

#search{
    text-align: center;
    margin-top: 200px;
}
#search form,
#search>div,
#search div.input-box-wrap,
#search div.input-box{
	margin-left: auto;
	margin-right: auto;
}
#search button{
    font-size: 100%;
    height: 100%;
    &:hover{
        cursor: pointer;
    }
}
#search>div{
	margin: 32px auto;
}
form{
	margin: 32px auto;
}

/*搜索框样式*/
div.input-box-wrap{
    height: 30px;
    width: 320px;
    position: relative;
    margin-bottom: 36px;
}
div.input-box{
    width: 30px;
    height: 100%;
    position: relative;
    background-color: $blue;
    padding: 0;
    border-radius: 20px;
    border: 4px solid $orange;
    overflow: hidden;
    

    input{
        height: 100%;
        width: 100%;
        font-size: 100%;
        display: none;
    }
}
.collapsed{
    cursor: pointer;
}
/*放大镜的尾巴*/

div.input-box-wrap div.tail,
div.input-box div.close{
	position: absolute;
	border-radius: 1px;
	background-color: $orange;
}
div.input-box-wrap div.tail{
	width: 30px;
	height: 3px;
	left: 172px;
	top: 31px;
	transform: translate(-50%,-50%) rotate(45deg);
	z-index: -1;
}

/*缩小搜索框的叉*/

.input-box{
    .shrink{
        width: 30px;
        height: 30px;
        position: absolute;
        top: 0;
        right: 10px;
        cursor: pointer;
        z-index: 1;
        display: none;
    }
    .close{
        width: 20px;
        height: 2px;
        right: -10px;
        top: 40px;
        transform:  translate(0, -50%) rotate(45deg);
    }
    .close.up{
        right: -10px;
	    top: -10px;
	    transform: translate(0, -50%) rotate(-45deg);
    }
}

/*==============
结果页面部分
================*/

#result{
    // display: none;
    ul{
        list-style: none;
        padding: 0;
    }
    li{
        color: black;
        padding-left: 6px;
        &:hover{
            background-color: $orange;
        }
        a{
            padding: 16px 16px 2px 24px;
            margin: 16px 0 0 0;
            display: block;
            background-color: $lightyellow;
        }
    }
}

style.css

@charset "UTF-8";
/*基本与全局样式*/
body {
  background-color: #2E94B9;
  font-size: 18px;
  color: white;
  width: 80%;
  margin: 10px auto;
}

ul, li, input, button, h1, h2, h3 {
  margin: 0;
  padding: 0;
}

input, button {
  border-width: 0;
  background-color: transparent;
  color: #FFFDC0;
  outline: none;
}

h1, h2, h3 {
  margin-bottom: 16px;
}

a {
  text-decoration: none;
  color: black;
}

.off {
  display: none;
}

/*============
搜索栏部分
==============*/
#search {
  text-align: center;
  margin-top: 200px;
}

#search form,
#search > div,
#search div.input-box-wrap,
#search div.input-box {
  margin-left: auto;
  margin-right: auto;
}

#search button {
  font-size: 100%;
  height: 100%;
}

#search button:hover {
  cursor: pointer;
}

#search > div {
  margin: 32px auto;
}

form {
  margin: 32px auto;
}

/*搜索框样式*/
div.input-box-wrap {
  height: 30px;
  width: 320px;
  position: relative;
  margin-bottom: 36px;
}

div.input-box {
  width: 30px;
  height: 100%;
  position: relative;
  background-color: #2E94B9;
  padding: 0;
  border-radius: 20px;
  border: 4px solid #F0B775;
  overflow: hidden;
}

div.input-box input {
  height: 100%;
  width: 100%;
  font-size: 100%;
  display: none;
}

.collapsed {
  cursor: pointer;
}

/*放大镜的尾巴*/
div.input-box-wrap div.tail,
div.input-box div.close {
  position: absolute;
  border-radius: 1px;
  background-color: #F0B775;
}

div.input-box-wrap div.tail {
  width: 30px;
  height: 3px;
  left: 172px;
  top: 31px;
  transform: translate(-50%, -50%) rotate(45deg);
  z-index: -1;
}

/*缩小搜索框的叉*/
.input-box .shrink {
  width: 30px;
  height: 30px;
  position: absolute;
  top: 0;
  right: 10px;
  cursor: pointer;
  z-index: 1;
  display: none;
}

.input-box .close {
  width: 20px;
  height: 2px;
  right: -10px;
  top: 40px;
  transform: translate(0, -50%) rotate(45deg);
}

.input-box .close.up {
  right: -10px;
  top: -10px;
  transform: translate(0, -50%) rotate(-45deg);
}

/*==============
结果页面部分
================*/
#result ul {
  list-style: none;
  padding: 0;
}

#result li {
  color: black;
  padding-left: 6px;
}

#result li:hover {
  background-color: #F0B775;
}

#result li a {
  padding: 16px 16px 2px 24px;
  margin: 16px 0 0 0;
  display: block;
  background-color: #FFFDC0;
}

index.js

var paraJack = {
    wikiItemBaseUrl: 'https://zh.wikipedia.org/wiki/',
    resultNum: 12
}

$(document).ready(function(){
    setEventHandler();
});

function setEventHandler() {
    //点击图标,展开搜索
    $('.input-box-wrap').on('click', '.collpased', function(event){
        expandSearchInput();
    });

    //ç‚¹å‡»× ï¼ŒæŠ˜å 
    $('.input-box-wrap').on('click', '.shrink', function(){
        shrinkSearchInput();
    });

    //提交搜索文本,显示结果
    $('form').on('submit', function(){
        //防止默认事件
        event.preventDefault();

        var $search = $('#search');
        var searchStr = $search.find('input').val(); //输入的文本

        $search.animate({
            marginTop: '0px'
        }, 500);
        $('form>p').hide();

        $.getJSON('https://zh.wikipedia.org/w/api.php?action=query&titles=' + encodeURIComponent(searchStr) + '&action=query&format=json&list=search&srsearch=' + encodeURIComponent(searchStr) + '&srlimit=' + paraJack.resultNum + '&srprop=snippet&callback=?',function(data){
				genResultDom(paraJack.resultNum);
				//根据需要的结果数量填充dom结构
				
				var $anchors = $('#result a');
				$.each(data.query.search,function(index,val){
					//根据结果修改Dom
					
					var $theAnchor = $anchors.eq(index),
						$p = $theAnchor.find('p'),
						$h2 = $theAnchor.find('h3'),
						title = val.title,	//结果项标题
						snippet = val.snippet;	//结果项内容提要
					$h2.html(title);
					$p.html(snippet);
					$theAnchor.attr({
						href: paraJack.wikiItemBaseUrl + title
						//用结果项标题生成URL
					});
				});
				$('#result').show();	//显示结果
		});
    });
}

function expandSearchInput () {
    var $result = $('#result');
    var $form = $('form');
    var $inputBoxWrap = $form.find('.input-box-wrap');
    var $inputBox = $inputBoxWrap.find('.input-box');
    var $tail = $inputBoxWrap.find('.tail');
    var $up = $inputBox.find('.up');
    var $down = $inputBox.find('.down');
    var $shrink = $inputBox.find('.shrink');
    var $input = $inputBox.find('input');

    $tail.animate({
        width: '0px'  //缩短搜索图标尾巴到0
    }, 500, function(){
        $inputBox.animate({
            //水平展开输入框包含块
            width: '200px',
            padding: '0px 45px 0px 15px'
        }, 500, function(){
            //将输入框包含块末尾的叉滑入输入框内(原来的位置$inputBox之外,而$inputBox的overflow属性设置为了hidden)
            $up.animate({
                top: '15px',
                right: '15px'
            }, 500);
            $down.animate({
                top: '15px',
                right: '15px'
            }, 500, function(){
                //显示输入框本身并获取焦点,
                //将输入框包含块设置为collapse类(在有该类的输入框包含块中点击才会触发收缩动画,因此在展开动画进行到此位置之前是不可能通过点击'关闭叉'上透明方块来运行收缩动画的)
                $input.show().focus();
                $inputBox.removeClass('collpased');
                $shrink.show();
                //显示用于接受'折叠搜索栏'点击的'关闭叉'上的透明方块			
            });
        });
    });
}
function shrinkSearchInput(){
    //点击输入框末尾的叉,动画折叠搜索栏为搜索图标
    
        var $result = $('#result'),
            $form = $('form'),
            $p = $('form>p'),
            $inputBoxWrap = $form.find('div.input-box-wrap'),
            $inputBox = $inputBoxWrap.find('div.input-box'),
            $tail = $inputBoxWrap.find('div.tail'),
            $up = $inputBox.find('div.up'),
            $down = $inputBox.find('div.down'),
            $shrink = $inputBox.find('div.shrink'),
            $input = $inputBox.find('input');
    
        //清空输入框内容,显示点击提示文本,隐藏之前的搜索结果
        $input.val('');
        $p.show();
        $result.hide();
    
        $('#search').animate({
            marginTop: '200px'
        },500);
    
        $up.animate({
                top: '-10px',
                right: '-10px'
            },500);
    
        $down.animate({
            top: '40px',
            right: '-10px'
        },500,function(){
            $inputBox.animate({
                width: '30px',
                padding: '0px'
            },500,function(){
                $tail.animate({
                    width: '30px'
                },500);
                $input.hide();	//隐藏搜索框
                $inputBox.addClass('collpased');
                $shrink.hide();	//隐藏接受‘收缩搜索栏’点击的透明块
            });
        });
    }

function genResultDom(resultNum) {
    if (typeof resultNum === 'number') {
        var $result = $('#result'),
            $ul = $result.html('<ul></ul>').find('ul');
        for (var i = 0; i < resultNum; i++) {
            $ul.append($('<li><a href="" target="_blank"><h3></h3><p></p></a></li>'));
        }
    }
}

wiki viewer 仿版

 wiki viewer 仿版

 wiki viewer 仿版