VueJs + Elements + Axios 我的书签页

概述

看了几天 Vue 文档了,今天应该实践一下了,做一个个人书签页面,记录自己的常用书签。

书签页构思草图

创建工程

vue install webpack "hellovue"

启动预览

npm run dev

值得注意的是 npm run dev 实际上执行的是 package.json 中的 script 脚本的如下命令:

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

也许你已经猜到了, 这个 webpack.dev.conf.js 文件是配置开发过程中的webpack构建文件。

接下来我们就开始修改 HelloWorld.vue 来实现书签页。

基本配置

index.html 中消除默认样式和添加公共样式:

*{
    margin:0;
    padding:0;
}
img{
    display: block
}
html{
    height:100%;
}
body{
    height:100%;
    margin:0;
}

引入 Elements UI 组件库

main.js 中添加如下内容:

 import Vue from 'vue'
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
 import App from './App'
 import router from './router'
 
 Vue.config.productionTip = false
+Vue.use(ElementUI);
 /* eslint-disable no-new */
 new Vue({
   el: '#app',
   router,
   components: { App },
   template: '<App/>'
 })

布局框架

src/HelloWorld.vue 中添加框架代码:

<el-container id="container">
    <el-header height="80px" ></el-header>
    <el-divider></el-divider>
    <el-container id="center-container">
        <el-aside width="300px"></el-aside>
        <el-container id="content-container"></el-container>
    </el-container>
    <el-divider></el-divider>
    <el-footer></el-footer>
</el-container>
#container{
    width: 100%;
    height: 100%;
    flex-direction: column;
    display: flex;
    overflow-x:hidden;
    overflow-y:scroll;
}

.el-divider{
    margin:0;
}

.el-header{
    background: #B3C0D1;
}

.el-footer{
    background: #B3C0D1;
}

#center-container{
    flex: 1;
}

#content-container{
    width: 100%;
    height: 100%;
    background: #e9eef3;
}

.el-aside{
    background: #d3dce6;
}

知识点

上面使用了 flex 布局,flex 布局是脱离盒模型布局的新布局, 是很常用而且很有用的布局方式。

布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。2009年,W3C 提出了一种新的方案—-Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。

任何一个容器都可以指定为 Flex 布局,行内元素也可以使用 Flex 布局:

.box{
  display: flex;
}

.box{
  display: inline-flex;
}

Webkit 内核的浏览器,必须加上-webkit前缀:

.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}

注意,设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。

flex-direction : 属性决定主轴的方向(即项目的排列方向), 上面使用的 column 意思是竖向,从上到下。

.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

flex-wrap : 默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行:

.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}

flex-flow : flex-direction 属性和 flex-wrap 属性的简写形式,默认值为 row nowrap。

justify-content : 在主轴上的对齐方式。

.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

align-items : 属性定义项目在交叉轴上如何对齐。

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

align-content : 定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

Axios加载JSON数据

axios 是基于promise用于浏览器和node.js的http客户端。

安装:

npm install axios

执行 get 请求:

axios.get('/test.json')
    .then(function (response) {
        console.log(response);
    })
    .catch(function (error) {
        console.log(error);
    });

src/HelloWorld.vue 中的 onCreate 生命周期中加载 json 数据:

import axios from 'axios'
export default {
    name: 'HelloWorld',
    data () {
    return {
        banners:[],
    }
    },
    created(){
        axios.get('http://qiniucdn.dp2px.com/test.json').then(response => {
            this.banners = response.data
        });
    }
}

then()方法是异步执行。就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题。

=> 符号是一种缩写,叫箭头函数, 上面的箭头函数补全如下:

function(response){
    this.banners = response.data
}

<template> 中使用 banners 对象来渲染数据:

<el-carousel id="banner" :interval="4000" type="card" height="200px">
    <el-carousel-item v-for="(item, key) in banners" :key="key">
        <el-image :src="item.url"></el-image>
    </el-carousel-item>
</el-carousel>

上面的 v-for 有三种形式的参数, 除了 item 下方的其他参数都是数组下标索引的别名。

<div v-for="(item, index) in items"></div>
<div v-for="(item, key) in items"></div>
<div v-for="(item, key, index) in items"></div>

v-for 默认行为试着不改变整体,而是替换元素。迫使其重新排序的元素,你需要提供一个 key 的特殊属性:

<div v-for="item in items" :key="item.id">
  {{ item.text }}
</div>

例如案例中的某处我们是这样用的:

<el-menu-item v-for="(item, index, key) in bookmarks" :key="key" :index="(index).toString()">
    <i class="el-icon-collection-tag"></i>
    <span slot="title"> {{ item.typename }} </span>
</el-menu-item>

实时上 indexkey 的值是一样的,都是数组下标索引的别名。

那如果是那样,其实我们也可以写成如下样子:

<el-menu-item v-for="(item, key) in bookmarks" :key="key" :index="(key).toString()">
    <i class="el-icon-collection-tag"></i>
    <span slot="title"> {{ item.typename }} </span>
</el-menu-item>

还值得注意的是上面的 :key:src , :interval 等都是 v-bind: 的缩写形式,意思是给组件绑定属性。

float vs inline-block

display的几个常用的属性值,inline , block, inline-block:

inline(行内元素):

  • 使元素变成行内元素,拥有行内元素的特性,即可以与其他行内元素共享一行,不会独占一行。
  • 不能更改元素的 height,width 的值,大小由内容撑开。
  • 可以使用 padding 上下左右都有效,margin 只有 left 和 right 产生边距效果,但是 top 和 bottom 就不行。

block(块级元素):

  • 使元素变成块级元素,独占一行,在不设置自己的宽度的情况下,块级元素会默认填满父级元素的宽度。
  • 能够改变元素的 height,width 的值。
  • 可以设置 padding,margin 的各个属性值,top,left,bottom,right 都能够产生边距效果。

inline-block(融合行内于块级):

  • 结合了 inline 与 block 的一些特点,结合了上述 inline 的第 1 个特点和 block 的第 2, 3个特点。
  • 用通俗的话讲,就是不独占一行的块级元素。

浮动和设置 inline-block 很多时候可以达到同样的效果,但是浮动会使元素脱离标准文本流,出现参差不齐的现象:

上面的中间 书签列表 布局中就使用了 inline-block 实现界面缩放的整体居中效果:

<div style="min-width:10px; margin:0 auto;" v-if='bookmarks.length>0'>     
    <el-card class="box-card" v-for="(item,key) in bookmarks[keyindex].datas" :key="key"
        style="display: inline-block; width:200px; margin:20px;">
        <!-- .... -->
    </el-card>
</div>

这里利用了 inline-block 不占一整行却可以设置宽高的特点,让它自己撑开父布局,而父布局整体居中。

构建

执行构建命令:

npm run build 

然后在 dist 目录下查看输出的静态文件,这里需要注意的是在构建前要修改路径配置:

  1. 修改 config/index.js 中的 assetsPublicPath 为相对路径:

    build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),
    
    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',
    
    //....
    }
    
  2. 修改 build/utils.js 中的添加一行 publicPath: 配置:

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
    return ExtractTextPlugin.extract({
    use: loaders,
    publicPath: '../../',
    fallback: 'vue-style-loader'
    })
    } else {
    return ['vue-style-loader'].concat(loaders)
    }
    

这个 build 目录下的 js 就是在执行 npm run build 的时候执行的命令, 而上面那个方法是对 css 中路径的修改来解决打包后 element ui 的 icon 不显示问题。

源码下载:https://github.com/lxqxsyu/Vue-Elements