走在前端的大道上
一.基础
1.vue项目初始化
新建目录 ss 和 test.js 文件:
mkdir ss
cd ss
touch test.js
初始化目录生成 package.json
npm init
npm set
用来设置项目初始化时默认值
$ 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的项目
安装选项可以参照下图
然后就可以在目录中看到生成vuedemo3文件夹
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')
})
在浏览器中查看(我安装了chrome游览器插件‘jsonView jsonViewer json formatter’,所以页面上的格式是美化过的)
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给组件绑定原生事件
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:{
}
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
})
}
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
7.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.
本节参考文章:vue中使用base64和md5
三.常见问题
1.vue-cli打包引发的 字体或图片 丢失问题
解决本地和服务器上资源url解析的问题
问题描述:
1.在img中的图片是完全正确的, 但css中background-image: url()
的图片怎么都找不到.
2.最尴尬的是: 在npm run dev的时候一切正常
解决方法:
在 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%;
}
更多问题总结:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。