3

走在前端的大道上


一.基础

1.vue项目初始化

新建目录 ss 和 test.js 文件:

mkdir ss
cd ss
touch test.js

初始化目录生成 package.json

npm init

npm set 用来设置项目初始化时默认值

clipboard.png

$ npm set init-author-name 'your name'
$ npm set init-author-email 'your email'
$ npm set init-author-url 'your name'
$ npm set init-license 'MIT'

2.vue-cli 安装

首先nodejs默认已经安装

1.1 如果你的电脑是没有安装过vue-cli,那么需要全局安装执行npm install vue-cli -g,用vue -V查看版本,用vue list查看可选工具

1.2 执行vue init webpack vuedemo3 在当前目录下创建vuedemo3的项目
安装选项可以参照下图

clipboard.png

然后就可以在目录中看到生成vuedemo3文件夹

clipboard.png

1.3 切换到vuedemo3文件夹
执行npm install,就下载了项目所需要的包依赖


3.vue挂载和渲染方式

    new Vue({
        el:'#app',
        router,
        template:<App/>,
        components:{App}
    })
或
    new Vue({
        router,
        template:<App/>,
        components:{App}
    }).$mount("#app");
    new Vue({
        router,
        render: h=>h(App)
    }).$mount("#app");
或
    new Vue({
        router,
        render: function(h){
            return h(App);
        )
    }).$mount("#app");

4.slot插槽

在子组件<hello>里

<slot name='world'></slot>

父组件使用

<hello>
    <span slot='world'>
        ....
    </span>
</hello>

5.获取本地的json数据(模拟服务端返回数据)

在项目中需要使用vue-resource来与后台进行数据交互,项目前期使用本地json数据来模仿后台获取数据的流程

说明:查看版本vue -V

操作方法:
a、项目结构:本地的json文件放在最外层和index.html同级,叫做db.json。
b、在build的dev-server.js进行加入代码,位置如截图:

var apiServer = express()
var bodyParser = require('body-parser')
apiServer.use(bodyParser.urlencoded({ extended: true }))
apiServer.use(bodyParser.json())
var apiRouter = express.Router()
var fs = require('fs')
apiRouter.route('/:apiName')
.all(function (req, res) {
  fs.readFile('./db.json', 'utf8', function (err, data) {
    if (err) throw err
    var data = JSON.parse(data)
    if (data[req.params.apiName]) {
      res.json(data[req.params.apiName])
    }
    else {
      res.send('no such api name')
    }

  })
})

apiServer.use('/api', apiRouter);
apiServer.listen(port + 1, function (err) {
  if (err) {
    console.log(err)
    return
  }
  console.log('Listening at http://localhost:' + (port + 1) + '\n')
})

clipboard.png

在浏览器中查看(我安装了chrome游览器插件‘jsonView jsonViewer json formatter’,所以页面上的格式是美化过的)

clipboard.png


6.vue组件绑定原生事件

vue使用element-ui的el-input监听不了回车事件,当然其他组件也有不能监听原生事件的

<el-input v-model="taskSeachText" @keyup.enter="handleClick"></el-input>

需要在事件后面加上.native

<el-input v-model="taskSeachText" @keyup.enter.native="handleClick"></el-input>

总结:写在一个封装好的组件上,有些标签的原生事件要.native 修饰符才能生效 #vue给组件绑定原生事件

clipboard.png

7.跨域请求配置

我们平时本地前端开发环境dev地址大多是 localhost:8080,而后台服务器的访问地址就有很多种情况了,比如 127.0.0.1:8889,当前端与后台进行数据交互时,自然就出现跨域问题(后台服务没做处理情况下)。

现在通过在前端修改 vue-cli 的配置可解决:
vue-cli中的 client/config/index.js 下配置 dev选项的 {proxyTable}:

proxyTable: {
  // proxy all requests starting with /api to jsonplaceholder
  '/api': {
    target: 'http://127.0.0.1:8889/api',
    changeOrigin: true,
    onProxyReq (proxyReq, req, res) {
    }
  }
}

实际上这是因为脚手架使用了中间件 http-proxy-middleware

源地址 转发地址
localhost:8080/api api.example.com/api
localhost:8080/api/notifications api.example.com/api/notifications

如果我们要去掉 api.example.com的api路径?

设置 pathRewrite

proxyTable: {
  '/api': {
    target: 'http://api.example.com',
    changeOrigin: true,
    pathRewrite: '^/api' : '',
    onProxyReq (proxyReq, req, res) {
    }
  }
}
源地址 转发地址
localhost:8080/api api.example.com
localhost:8080/api/notifications api.example.com/notifications
代理的好处 代理的问题
解决开发时跨域问题 代码需要设置环境变量,prod环境下不存在 http-proxy-middleware 中间件

8.axios 配置

新建 ajax.js

import axios from 'axios'
import store from '../store'
// 超时设置
const http = axios.create({
    timeout: 5000,
    baseURL: process.env.API_URL
})
或
// axios.defaults.baseURL = 'https://api.github.com';

// http request 拦截器
// 每次请求都为http头增加Authorization字段,其内容为token
http.interceptors.request.use(
    config => {
        if (store.state.user.token) {
            config.headers.Authorization = `token ${store.state.user.token}`;
        }
        return config
    },
    err => {
        return Promise.reject(err)
    }
);
export default http

在入口文件 main.js 引入 ajax.js,并将其挂在到 Vue 全局方法下,即注册到Vue原型上。这样在.vue文件中直接使用this.$axios即可。当然你也可以在每个需要用到axios的文件中单独引入。

import axios from './ajax'
...
Vue.prototype.$axios = axios

*.vue

 methods: {
    // 请求到数据并赋值给data里声明的变量
      getData () {
        this.$axios.get('../../static/data/index.json').then((response) => {
          this.data = response.data
        }, (response) => {
          // error
        })
      }
    }

一些常用的库也可以挂载到 Vue 的原型上,避免在每个.vue单页面频繁import引入

9.任意两个组件之间的通信

非父子间的组件通信官方的叫法 global bus

// one.vue
<template>
  <div>
      这是one组件
      <button @click="commit">给two组件发送信息</button>
      <p> {{ message }}</p>
  </div>
</template>
<script type="text/javascript">
import { bus } from './bus'
export default {
    name: 'one',
    data () {
        return {
            message: '',
        }
    },
    methods:{
        commit () {
            bus.$emit('sendMsg',{
                msg: '这条信息来自于one'
            })
        }
    },
    mounted () {
        bus.$on('backMsg', (data) => {
            this.message = data.msg;
        })
    }
}
// two.vue
<template>
    <div @click="commit">
        <p>这是two组件<button @click="commit">给one组件发送信息</button></p>
        <p>{{ message }}</p>
    </div>
</template>
<script type="text/javascript">
import { bus } from './bus'
export default {
    name: 'two',
    data () {
        return {
            message: ''
        }
    },
    methods:{
        commit () {
            bus.$emit('backMsg',{
                msg: '这条信息来自于two'
            })
        }
    },
    mounted () {
        bus.$on('sendMsg', (data) => {
            this.message = data.msg;
        })
    }
}
</script>

最关键的bus,却是最简单的

// bus.vue
<script>
import Vue from 'vue'
export default {
    bus: new Vue(),
}
</script>

二.常用组件

1.vue-router

1.动态路由

    routes:[
        {
            path:'/cart',
            name:'cart'
            component:Cart
        },
        {
            path:'/goods/:goodId/post/:name',
            name:'goods'
            component:goodsList
        }
    ]
    
    html:
        <span>{{$route.params.goodId}}</span>
        <span>{{$route.params.name}}</span>

2.嵌套路由

    routes:[
        {
            path:'/goods',
            name:'goods'
            component:goodsList,
            children:[
                {
                    path:'title',    // 这里title不能加 /
                    name:'title',
                    compoent: Title
                },
                {
                    path:'img',  
                    name:'img',
                    compoent: Image
                }
            ]
        }
    ]

    html:
        <router-link to="/goods/title">显示标题</router-link>
        <router-link to="/goods/img">显示图片</router-link>
        <router-view></router-view>

备注:

<router-view></router-view>    标签是盛放一级路由的
<router-link to="/goods/title"></router-link>   是路由跳转

3.编程路由(通过js来实现页面跳转)

    $router.push("name")     //    name=/title
    $router.push({path:"name"})
    $router.push({path:"name?goodId=123"}) 或者 $router.push({path:"name",query:{goodId:123}})
    $router.go(1)
    html获取参数
        <span>{{$route.query.goodId}}</span>    
  

备注:
获取页面跳转(js $router.push("name") )的参数 $route.query
获取路由的参数$route.params

4.命名路由和命名的视图

命名的路由

    <router-link :to="{name:'cart'}"></router-link>
    <router-link :to="{name:'goods',params:{goodId:123}}"></router-link>

命名的视图

    <router-view></router-view>   
    <router-view name="title"></router-view>   
    <router-view name="img"></router-view>   

    routes:[
    {
        path:'/goods',
        name:'goods'
        components:{
            default:GoodsList,
            title:Title,
            img:Image
        }
    },{
        path:'/cart',
        name:'cart'
        component:Cart
    }]


2.vue-Resource

vue-Resource 和 axios区别:resource是挂载到vue实例里面的axios是暴露了axios全局变量;axios的失败回调通过catch捕获

公用地址配置

http:{ //和methods 一级(并列)
    root: "http://"    
}

拦截器interceptors

    munted:function(){
        Vue.http.interceptors.push(function(request,next){
                console.log("request init")
                next(function(response){
                    console.log("response init")
                    return response
                })
            })
    },
    methods:{
    
    }

clipboard.png

REST风格,7种API

1.get(url,[options])

methods:
    //同Vue.http.get 
    this.$http.get('package.json',{ //http://www.imooc.com/course/AjaxCourseMembers?ids=796
        params:{
            userId:"101"
        },
        headers:{
            token:"abcd"
        }
    }).then(res => {
        this.msg = res.data;
    },error =>{
        this.msg = error
    })

2.head(url,[options])

3.delete(url,[options])

4.jsonp(url,[options])

methods:
    this.$http.jsonp('http://www.imooc.com/course/AjaxCourseMembers?ids=796',{
    this.msg = res.data;
})

5.post(url,[body],[options])

methods:
    this.$http.post('package.json',{
            userId:"102"
        },{
        headers:{
            access_token:"abc"
        }
    }).then(res => {
        this.msg = res.data;
    },error =>{
        this.msg = error
    })

6.put(url,[body],[options])

7.patch(url,[body],[options])

8.自定义

methods:
    http:function(){
        this.$http({
            url:'package.json',
            methods:'GET',
            params:{
                userId:'103'
            },
            header:{
                token:'123'
            },
            timeout:50,
            before:function(){
                console.log("before init")
            }
        }).then(function(res){
            this.msg = res.data
        })
    }

clipboard.png

3.axios

vue-Resource 和 axios区别:resource是挂载到vue实例里面的axios是暴露了axios全局变量;axios的失败回调通过catch捕获

公用地址配置

axios.defaults.baseURL = 'https://112...Server'   

拦截器interceptors

munted:function(){
    axios.interceptors.request.use(function(request){
        console.log("request init")
        return request
    })
    axios.interceptors.response.use(function(response){
        console.log("request init")
        return response
    })
},
methods:{

}

1.axios.request(config)

2.axios.get(url[,config])

axios.get('package.json',{ //http://www.imooc.com/course/AjaxCourseMembers?ids=796
    params:{
        userId:"999"
    },
    headers:{
        token:"jack"
    }
}).then(res => {
    this.msg = res.data;
}).catch(error =>{
    console.log('error init')
})

3.axios.head(url[,config])

4.axios.delete(url[,config])

5.axios.options(url[,config])

6.axios.post(url[,[data[,config]])

axios.post('package.json',{ //http://www.imooc.com/course/AjaxCourseMembers?ids=796
        userId:"888"
    },{
    headers:{
        token:"tom"
    }
}).then(res => {
    this.msg = res.data;
}).catch(error =>{
    console.log('error init')
})

7.axios.put(url[,[data[,config]])

8.axios.patch(url[,[data[,config]])

9.自定义

methods:
    http:function(){
        axios({
            url:'package.json',
            methods:'post',
            params:{ // get方式传参
                userId:'111'
            },
            data:{  // post方式传参
                userId:'666'
            },
            header:{
                token:'http-test'
            }
        }).then(function(res){
            this.msg = res.data
        })
    }

4.babel-polyfill

5.babel-runtime

6.better-scroll

地址
当 better-scroll 遇见 Vue


7.fastclick

地址
FastClick 原理解析
中文翻译


8.vue-lazyload

地址
中文文档

9.stylus

同时需要stylus-loader


10.js-base64

1.在项目根目录下安装

cnpm install --save js-base64

2.在项目文件中引入

let Base64 = require('js-base64').Base64;

3.在项目文件中使用

Base64.encode('dankogai');  // ZGFua29nYWk=
Base64.encode('小飼弾');    // 5bCP6aO85by+
Base64.encodeURI('小飼弾'); // 5bCP6aO85by-

Base64.decode('ZGFua29nYWk=');  // dankogai
Base64.decode('5bCP6aO85by+');  // 小飼弾
// note .decodeURI() is unnecessary since it accepts both flavors
Base64.decode('5bCP6aO85by-');  // 小飼弾

11.js-md5

1.在项目根目录下安装

cnpm install --save js-md5

2.在项目文件中引入

import md5 from 'js-md5';

3.在项目文件中使用

md5(''); // d41d8cd98f00b204e9800998ecf8427e
md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0

// It also supports UTF-8 encoding
md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07

// It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
md5([]); // d41d8cd98f00b204e9800998ecf8427e
md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e

// Different output
md5(''); // d41d8cd98f00b204e9800998ecf8427e
md5.hex(''); // d41d8cd98f00b204e9800998ecf8427e
md5.array(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
md5.digest(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
md5.arrayBuffer(''); // ArrayBuffer
md5.buffer(''); // ArrayBuffer, deprecated, This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.

clipboard.png

clipboard.png
本节参考文章:vue中使用base64和md5


三.常见问题

1.vue-cli打包引发的 字体或图片 丢失问题

解决本地和服务器上资源url解析的问题

问题描述:

1.在img中的图片是完全正确的, 但css中background-image: url()的图片怎么都找不到.
2.最尴尬的是: 在npm run dev的时候一切正常

clipboard.png

解决方法:

在 config/index.js 中修改 assetsPublicPath 为 ./

在 build/utils.js 中的 ExtractTextPlugin.extract 传入参数 publicPath: '../../'

2.axios的 post 请求后台接受不到

axios的 post 请求后台接受不到!axios默认是 json 格式提交,确认后台是否做了对应的支持;
若是只能接受传统的表单序列化,就需要自己写一个转义的方法...
当然还有一个更加省事的方案,装一个小模块qs

npm install qs -S


// 然后在对应的地方转就行了..单一请求也行,拦截器也行...我是写在拦截器的.
// 具体可以看看我 axios 封装那篇文章

//POST传参序列化(添加请求拦截器)
Axios.interceptors.request.use(
  config => {
    // 在发送请求之前做某件事
    if (
      config.method === "post"
    ) {
      // 序列化
      config.data = qs.stringify(config.data); // ***** 这里转义
    }

    // 若是有做鉴权token , 就给头部带上token
    if (localStorage.token) {
      config.headers.Authorization = localStorage.token;
    }
    return config;
  },
  error => {
    Message({
      //  饿了么的消息弹窗组件,类似toast
      showClose: true,
      message: error,
      type: "error.data.error.message"
    });
    return Promise.reject(error.data.error.message);
  }
);

3.element-ui 2.0 input组件输入数字

element-ui 2.0 表单或者input组件 验证输入的数字检测出来是string

数字类型的验证需要在 v-model 处加上 .number 的修饰符,这是 Vue 自身提供的用于将绑定值转化为 number 类型的修饰符。el-input 的 type 属性设置为 "number"

<el-form-item label="年龄" prop="age">
    <el-input type="number" v-model.number="ruleForm2.age"></el-input>
</el-form-item>

4.element-ui 2.0 table组件 添加border属性后多了滚动条

解决方法:

.el-table__body-wrapper, .el-table__footer-wrapper, .el-table__header-wrapper{
    width: 101%;
}

更多问题总结:

  1. Vue 脱坑记 - 查漏补缺...
  2. VUE使用element-ui所遇

参考文章1 , 参考文章2



于梦中2010
2.1k 声望181 粉丝

前端菜鸟儿,请多关照!


« 上一篇
atom那些事
下一篇 »
git 从零开始