《前端导航网站》

343 阅读5分钟
  1. html里默认的meta viewpoint 在手机上用户可以双指放大页面,这个项目里不需要,可以去taobao.com复制它的meta。

  2. 给body加一个border,虽然边界不是页面的全部,但是给body加背景颜色的时候,浏览器会智能地把颜色扩展到整个页面。

3. input输入框有一个默认的border,在给input加圆角的时候,需要用一个新的border覆盖掉,或者把border设为none,圆角才会出现。

border-radius: 4px;
border: 1px solid #ddd;  /*输入框边界色,一种灰色*/
  1. icon使用:

symbol引用,使用步骤如下:

第一步:拷贝项目下面生成的symbol代码: //at.alicdn.com/t/font_8d5l8fzk5b87iudi.js 把它放在页面的js引用前边就可以 <script src="//at.alicdn.com/t/font_1710001_hyt1a74rpt9.js"></script>

第二步:加入通用css代码(引入一次就行):

<style type="text/css">
    .icon {
       width: 1em; height: 1em;
       vertical-align: -0.15em;
       fill: currentColor;
       overflow: hidden;
    }
</style> //放到head里,css的引用前边就可以

第三步:挑选相应图标并获取类名,应用于页面:

<svg class="icon">
    <use xlink:href="#icon-xxx"></use>  //'-xxx'填图标的名字
</svg>  //放到图标所在的位置就可以
  1. a标签的使用:

想做到点击下方固定好的方块,跳转到相应的页面。每个方块是一个div元素,可以使用a标签,把div标签框住。以bilibili为例:

<a href="https://www.bilibili.com/">
    <div class="site">
        <div class="logo">
            <img src="./images/bilibili.jpg" />
        </div>
        <div class="link">bilibili.com</div>
    </div>
</a>

a标签是span元素,但是它可以包div,特例。但是a标签有默认的样式,会把页面变成这样:

所以要把a标签的样式reset:

a {
  color: inherit;
  text-decoration: none;
}
  1. 引入jQuery库,两种方法:1.下载jQuery代码

    2.bootcdn:

    把min.js那句代码放在script标签里,引入html。只要放在main.js那句代码前边就可以。

  2. 点击新增网站,弹出一个对话框“你要添加什么网址?”,在对话框里输入网址,然后通过jQuery创建一个li元素并且插入到页面里,也就是下方的方块。然后点击这个新增的网址,跳到相应页面,但是再次返回到原页面时,发现新增的那个方块消失了。怎么解决这个问题呢?

    1. 需要一个数据结构(hashMap数组),用于存储每个新增的网站。监听新增网站那个div,如果点击,先获取到用户输入的网址url,然后把对应的li元素的信息以对象的形式push进hashMap数组里,然后调用render函数(用于重新渲染页面,遍历hashMap,把hashMap里的所有对象插入到页面中)。
    2. 有了一个存储这些新增元素的数组,还是解决不了离开页面方块消失的问题。需要用到本地存储localStorage。
    window.onbeforeunload = () => {     //监听离开页面的事件
      console.log("离开页面");
      const string = JSON.stringify(hashMap); //localStorage只能存字符串,对象=>字符串
      localStorage.setItem("x", string); //接收key,value的形式,把hashMap存在本地
    }
    

    当监听到离开当前页面时,就把hashMap以键值对的形式存进localStorage里。当我再次回到当前页面时,读取localStorage里的值。

    const x = localStorage.getItem("x"); //x目前还是字符串
    const xObject = JSON.parse(x); //字符串=>对象
    

    在哪看localStorage?

    localStorage会永久保留在浏览器中,关闭页面也不会消失,除非用户手动清除。localStorage的键值对只支持字符串。所以如果不是字符串的类型要存进localStorage里,比如对象,要使用JSON.stringify;把字符串转换成对象:JSON.parse。

    使用了hashMap数组存储li元素后,就可以不用在html里写li了,除了最后一个新增网站外,可以直接在JS里用render函数渲染初始的收藏网站。

    const $siteList = $(".siteList");
    const $last = $siteList.find(".last");
    
    const x = localStorage.getItem("x"); //x目前还是字符串
    const xObject = JSON.parse(x); //字符串=>对象
    //用户第一次进来,初始状态,还没有新增时,
    //localStorage里是空,没有xObject,让hashMap等于初始的那些元素。
    const hashMap = xObject || [
      { logo: "A", logoType: "text", url: "https://www.acfun.cn/" },
      {
        logo: "./images/bilibili.jpg",
        logoType: "image",
        url: "https://www.bilibili.com/"
      },
      { logo: "./images/GitHub.png", logoType: "image", url: "https://github.com/" }
    ];
    
    const render = () => {      //渲染hash数组
      $siteList.find("li:not(.last)").remove(); //在渲染之前,把之前的li删掉,避免重复
      hashMap.forEach(node => {
        const $li = $(`<li>
        <a href="${node.url}">
            <div class="site">
            <div class="logo">${node.logo[0]}</div>
            <div class="link">${node.url}</div>
            </div>
        </a>
        </li>`).insertBefore($last);
      });  //遍历hashMap,先把之前的从页面删掉,再把所有的元素插入页面
    };
    render();
    
    $(".addButton").on("click", () => {
      let url = window.prompt("你要添加什么网址?"); //url获取到用户输入的内容
      //点击.addButton,弹出弹框
      if (url.indexOf("http") === -1) {
        //window.prompt("请输入带有http的网址"); 用户体验不好
        url = "https://" + url;
      } //如果用户输入的网址不带http,就自动为用户添加
      hashMap.push({ logo: url[0], logoType: "text", url: url });
      render();
    });
    
    window.onbeforeunload = () => {
      //监听离开页面的事件
      console.log("离开页面");
      const string = JSON.stringify(hashMap); //localStorage只能存字符串,对象=>字符串
      localStorage.setItem("x", string); //接收key,value的形式,把hashMap存在本地
    };
    

    现在页面的显示有一些问题,logo下方的link文本太长了,不需要前边的'https://www.',这一部分需要在render函数里通过jQuery创建元素时修改.link的文本值。原先是直接${node.url},即取全部url,现在要把url前边的http等删掉。利用字符串的replace方法。

    const simplifyUrl = url => {   //简化下边显示的link文本
        return url
            .replace("https://", "")
            .replace("http://", "")
            .replace("www.", "");
    };
    

    str.replace(substr,newstr) 查找str中的第一个substr子串,把它替换成newstr,返回新的字符串。如果str中没有substr,那就返回原字符串,即str。

    同时还发现一个bug,如果用户输入的网址很长,如:'juejin.im/editor/post…', 那么显示在下方的文本也会很长,在删掉了前边的http://之后,我也不想要后边以/开头的内容。只显示'juejin.im'就可以。优化simplifyUrl函数:

    const simplifyUrl = url => {   //简化下边显示的link文本
        return url
            .replace("https://", "")
            .replace("http://", "")
            .replace("www.", "")
            .replace(/\/.*/, "");  //正则表达式,删掉以/开头的内容
    };
    
  3. 还需要一个功能:删除下方的网站。在每个li元素中,再加一个.close元素,实现点击方块右上角的close,就把这个方块删掉。

怎么实现? 在render函数里,遍历hashMap,创建li元素时,再增加一个.close子元素,里边包裹icon图标,在页面显示。(需要两个以上图标,重新生成代码,这句代码是所有图标的代码,直接在html里写这一句就可以<script src=''></script>

问题1:因为.close元素还是在a标签里,所以点击它就相当于跳转到a标签。我需要用JS的阻止冒泡,stopPropagation(),使点击close时不触发a标签。

问题2:但是可能由于a标签太灵敏,不好用。所以我们不用a标签,用JS的click点击事件绑定每个li元素。在每次创建完li元素后,把该 $li 对象绑定一个点击事件:跳转到对应的页面。这里我们使用了window.open()

阻止冒泡后,开始绑定close自己的事件:点击close后,先阻止冒泡,然后把该close所在的li元素从hashMap里删除,再重新渲染render。

const render = () => {      //渲染hash数组
  $siteList.find("li:not(.last)").remove(); //在渲染之前,把之前的li删掉,避免重复
  hashMap.forEach((node, index) => {
    const $li = $(`<li>    
        <div class="site">
            <div class="logo">${node.logo[0]}</div>
            <div class="link">${simplifyUrl(node.url)}</div>
            <div class='close'>              <!--添加一个关闭图标-->
                <svg class="icon">
                    <use xlink:href="#icon-close"></use>
                </svg>
            </div>
        </div>    
    </li>`).insertBefore($last);
    $li.on("click", () => window.open(node.url)); //新开一个窗口,用JS代替a标签。因为用a标签,阻止冒泡不好用
    $li.on("click", ".close", e => {
      e.stopPropagation(); //阻止冒泡,点击关闭时不跳转页面,不触发爸爸的事件
      hashMap.splice(index, 1);
      render();
    });
  });
};

细节:我们在每次离开页面时,把hashMap存进本地存储里,然后再次渲染页面时,从本地存储里读取xOject再赋给hashMap。但是用户第一次进来的时候,xObject为空,此时需要给一个保底值,即如果xObject为空,就把hashMap赋一个初始值,初始显示在页面上的内容。然后我在页面里新增网站,再删除网站,如果把所有网站全删没,localStorage里的x属性对应的就是一个空数组了,即xObject=[],但是并不是null,所以hashMap还是会等于xObject。

PC端的宽度一般是固定的,就算拉小窗口,宽度也不会变,比如淘宝。