vue 实战各种小技巧(长期更新)
1. vue-cli 构建项目
- 命令行
# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack your-project-name
# 安装依赖,走你
$ npm install
# 进入项目
$ cd your-project-name
# 开发版本打包并运行
$ npm run dev
# 线上环境整个项目打包 生成 dist 可以直接部署到服务器上的文件夹
npm run build
2. 项目模板中使用 less 方法
原文地址
vue-cli 构建的项目默认是不支持 less 的,需要自己添加。
- 首先安装 less 和 less-loader ,在项目目录下运行如下命令
# npm安装
$ npm install less less-loader --save-dev
# 或者使用 yarn
$ yarn add less less-loader --dev
- 安装成功后,打开
build/webpack.base.conf.js
,在 module.exports = 的对象的 module.rules 后面添加一段:
module.exports = {
// 此处省略无数行,已有的的其他的内容
module: {
rules: [
// 此处省略无数行,已有的的其他的规则
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
}
]
}
}
image.png
- 最后在代码中的 style 标签中 加上 lang="less" 属性即可
<style scoped lang="less">
</style>
image.png
- 之后在项目中测试是否成功
npm install less less-loader --save-dev
npm run dev
image.png
- 在浏览其中打开相应页面,这个页面是
/
根页面点击跳转过来的子路由
image.png
image.png
可以看到样式编译成功了 哦耶~
3. 在 router 下的路由文件里设置格式,将页面上路由中默认显示的 #/
给去掉
// 去掉路由中自带的 #/ 这种东西
mode: 'history',
image.png
- 需要注意的是使用了
history
之后需要在服务器部署时增加一些配置,具体方法插件下面官方写的配置方法
4. 引入 jquery
- 安装
npm install jquery --save
- 配置
image.png
image.png
// 先在顶部引入 webpack
const webpack = require('webpack')
// plugins 中添加
new webpack.ProvidePlugin({
'window.jQuery': 'jquery', // 为了兼容其他的插件
jQuery: 'jquery',
$: 'jquery'
})
- 使用
image.png
5. :class 使用表达式
:class="{'想要改变的类名': 判断条件}
- 示例图片
image.png
6. DOM 事件修饰符
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
- 示例,如下图所示,这样写的话点击了 li 内部的元素的话不会影响 li 的 click 的点击事件
image.png
7. vue 使用 clipboard 实现复制功能
- 安装依赖 clipboard.js
npm install clipboard --save
- 在需要使用的地方 require 引用
var clipboard = require('clipboard');
- 在页面加载后调用该方法即可
image.png
8. 解决 vue-resource 的跨越问题
我这里是 vue-cli 基于 webpack 的项目(注意:在修改了 proxyTable 之后需要在命令行中
npm run dev
重新运行下项目,否则是不会有效果的呀~)
- 错误信息
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
- 解决方法:
先找到对应的配置 js 文件中的 proxyTable
image.png
修改相应的配置
image.png
再在 main.js 中配置 vue-resource 的格式,不配置的话是无法向后台传递参数的
image.png
在 vue 文件中的使用
data 中绑定相应的静态配置
image.png
methods 增加相应的方法
image.png
mouted 在 data 数据挂载到实例对象的时候 ,请求页面数据,实现页面的正常显示
image.png
9. vue-router 单页之间如何在 js 中跳转
- 三种写法
// 字符串
this.$router.push('/home/first')
// 对象
this.$router.push({ path: '/home/first' })
// 命名的路由
this.$router.push({ name: 'home', params: { userId: wise }})
image.png
10. vuex 实现组件之间数据的传递
根据 state 可以实时的获取到数据
原文地址
- 安装
npm install vuex --save
- 在 src 文件夹中新建一个 stroe 文件夹,并在目录下新建一个 index.js 文件(已有的话请忽略),index.js 文件编辑如下
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
let store = new Vuex.Store({
state: {
formData: {} // 企业提交数据表单对象
}
});
export default store;
- 在 src 目录下的 main.js 文件中引入 vuex 文件,并在实例化时添加配置
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store'; // 引入 vuex
Vue.config.productionTip = false;
Vue.http.options.emulateJSON = true;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 需要在添加
components: { App },
template: '<App/>'
});
- 之后就可以直接在需要的组件中直接引用,引用具体示例如下
image.png
image.png
控制台成功输出
image.png
11. .eslintrc.js 文件 rules 增加设置
12. vue 表单操作
13. 解决使用 vux 组件库时 与 rem 设置冲突带来的问题
- 思路
将之前 rem 计算的数值
html font-size: "100px"
,改到12px
,之后连锁的将 less 中计算和引用的的值也改下,之后就可以了,尽量做到少量的修改即可
- 将之前的 js 计算 rem 数值脚本修改相应的数值
image.png
改过之后的
image.png
- 修改 less
image.png
改过之后的
image.png
- 之后就可以是 rem 和 vux 基本正常了
14. 通过 watch 动态的监测路由跳转(跳转时)和 APP.vue 中设置 created 方法实时监测 path (刷新时),来实现 header 文字的改变
- header.vue
watch: {
'$route' (to, from) {
// 检测路由改变 header 内容
if (to.name === 'Index') {
this.$store.state.PageTitle = '预约领号';
this.$store.state.isShowBack = false;
} else if (to.name === 'PreferentialDescription') {
this.$store.state.PageTitle = '优惠说明';
this.$store.state.isShowBack = true;
} else if (to.name === 'RuleIntroduction') {
this.$store.state.PageTitle = '规则简介';
this.$store.state.isShowBack = true;
} else if (to.name === 'ReservationSuccess') {
this.$store.state.PageTitle = '预约排号';
this.$store.state.isShowBack = true;
}
}
}
15. vue-router spa (单页)需要的 nginx 配置,防止出现 404 的情况
image.png
照着上方的图将代码复制至服务器的 nginx.config 配置文件即可
- ssh 远程登录服务器
ssh username@ipaddress
enter your password
- 查找服务器中的 nginx 相关目录,我这边是 nginx 服务器
whereis nginx
image.png
-
/etc/nginx
这个是 nginx 相关配置的目录 -
/usr/share/nginx
是静态文件的目录 - 进入 html 目录,这个就是默认的存放项目文件的目录
image.png
- 修改 nginx 默认的配置文件
# 首先进入配置文件目录
cd /etc/nginx
ls
# 查看配置文件
cat nginx.config
# 复制一份原始的配置文件
cp nginx.config nginx.config.back
# 按照上面 vue-router 的需求修改配置文件
vi nginx.config
# 进入编辑状态
I
# 修改文件
location / {
try_files $uri $uri/ /index.html;
}
# 之后保存并退出
esc
:
wq
# 再次查看是否已修改成功
cat nginx.config
# 重载 nginx 配置文件(必须重载,不然修改的是不会生效的!)
nginx -s reload
image.png
- 上面的步骤操作完成之后便解决了 vue-router spa 带来的刷新页面 404 的问题了,哦耶~
16. 与后台 API 进行通信时,Content-Type
请求文本格式为统一带来的问题
- 问题截图
image.png
后台返回 415 Unsupported Media Type
对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。
- 产生错误的原因:
这里使用的是
post
请求,后台的请求文本格式为Content-Type:application/json;charset=UTF-8
但是这里使用的是默认的Content-Type:application/x-www-form-urlencoded
所以造成的此次错误
- 解决方法
在提交数据之前使用
image.pngJSON
的stringify
方法将数据转换为 json 格式的文本即可,如下图所示
JSON.stringiy()
JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,如果指定了replacer是一个函数,则可以替换值,或者如果指定了replacer是一个数组,可选的仅包括指定的属性。
17. 清除 .vue
文件在 vscode 编辑器中格式化时默认添加的分号和双引号的规则
image.png
- 问题
因为
vue-cli
项目创建后会默认的增加.eslintrc.js
eslint 规则文件来帮助我们更好的统一代码的规范性,但是现在的趋势是省略javascript
代码书写时在末尾添加的分号,但是 vscode 编辑器因为装了vetur
这个插件,所以还是会像之前的那样默认追加,使得项目报 eslint 语法的错误,单双引号也是相同的问题
- 解决方法
先安装扩展插件
image.pngPrettier - Code formatter
之后在顶部菜单栏依次操作:【文件】->【首选项】->【设置】->【用户设置】
最后增加下面的规则代码片段
"prettier.singleQuote": true,
"prettier.semi": false
18. 之前的删掉了,等待更新中......
19. 给 vue
挂载全局方法
- 找到
main.js
文件进行编辑,这里以axios
为例演示
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.axios = axios
- 使用方法 某个
.vue
文件的sccript
中如下编辑
Vue.axios.post('url', { name: '' })
.then(response => {
console.log(response)
})
.catch(response => {
console.log(response)
})
20. axios
不兼容 ie 的问题解决
- 问题描述
image.png
在 IE 浏览器下会报 “Promise”未定义" 的错误
- 资料
image.png
问题解决参考地址
- 解决方法
使用 babel-polyfill 这个包
- 装包
yarn add babel-polyfill --dev
- 之后在
main.js
文件中引入包即可
import 'babel-polyfill'
image.png
- 测试可兼容至 IE8+
image.png
- 更新 优化进阶 已经过测试
参考文章里面有详细的解释:babel-polyfill使用与性能优化
image.png
目的是为了打包出更小的体积,下图是使用新方法打包出的体积,用上面的方法打包出来是2.64MB
- 解决方法 将之前引入的
babel-polyfill
换成core-js/es6/promise
这个是vue-cli
脚手架就有的包无需再装了
import 'core-js/es6/promise' // 解决 axios 兼容 IE 问题
image.png
21. 组件封装,这里以 bootstrap 的 modal 模块为例
- 先写组件,在
src -> components
目录下新建一个文件夹msgmodal -> index.vue
,编辑如下
<template>
<!-- 弹窗 -->
<div class="modal fade" tabindex="-1" role="dialog" id="myModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<!-- <h5 class="modal-title"></h5> -->
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>{{ modalMsg }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">确定</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MsgModal', // 定义的组件名称 使用时写法:msg-modal
props: ['modalMsg'] // 定义的与父级通信的属性值 使用时写法:modal-msg
}
</script>
<style scoped>
</style>
- 在具体的
.vue
文件使用组件,方法如下,这里是用的动态绑定的方法传递属性的值
<!-- template -->
<!-- 弹窗 -->
<msg-modal :modal-msg="modalMsg"></msg-modal>
// script
import MsgModal from '@/components/msgmodal'
export default{
name:'App',
components: { MsgModal },
data () {
return {
// 弹窗信息 在执行操作时使用
modalMsg: ''
}
}
}
- 测试,已实现可以实时更新内容了
image.png
22. 在 router -> index.js
按需引入模块,优化 SPA
页面的性能
- 源码
import Vue from 'vue'
import Router from 'vue-router'
import VueResource from 'vue-resource'
// import index from '@/index'
// import companyapply from '@/companyapply'
// import choosenumber from '@/choosenumber'
// import statelist from '@/statelist'
Vue.use(Router)
Vue.use(VueResource)
export default new Router({
// 去掉路由中自带的 #/ 这种东西
mode: 'history',
routes: [
{
path: '/',
name: 'index',
component: () => import('@/index')
},
{
path: '/companyapply',
name: 'companyapply',
component: () => import('@/companyapply')
},
{
path: '/choosenumber',
name: 'choosenumber',
component: () => import('@/choosenumber')
},
{
path: '/statelist',
name: 'statelist',
component: () => import('@/statelist')
}
]
})
23. 在 Vue
上挂载 vux
库中的 LoadingPlugin
组件
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import { LoadingPlugin } from 'vux' // 引入 looding 组件
import App from './App'
import store from './store' // 引入 vuex
import router from './router'
Vue.config.productionTip = false
Vue.http.options.emulateJSON = true
Vue.use(LoadingPlugin) // 挂载 loading 组件
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 需要在添加
components: { App },
template: '<App/>'
})
-
.vue
文件中具体的使用示例:
// loading
this.$vux.loading.show({
text: '数据提交中
})
// 隐藏 loading
this.$vux.loading.hide()
24. 解决:使用 axios
默认发送的是 application/json;charset=UTF-8
这种格式的数据后台无法读取的问题
后台需要的是
application/x-www-form-urlencoded
这样的数据格式
参考地址
- 问题截图
image.png
- 需要的格式截图
image.png
-
解决方法
- 使用
qs
模块,转换数据格式
image.png
- 源码
import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题 -> name=hehe&age=10 axios.post(postAPI,qs.stringify(postData)) .then(request => { console.log(request) }) .catch(error => { console.log(error) })
- 使用
25. 化繁为简的Watchers
- 场景还原:
created(){
this.fetchPostList()
},
watch: {
searchInputValue(){
this.fetchPostList()
}
}
组件创建的时候我们获取一次列表,同时监听input框,每当发生变化的时候重新获取一次筛选后的列表这个场景很常见,有没有办法优化一下呢?
- 招式解析:
首先,在watchers中,可以直接使用函数的字面量名称;其次,声明immediate:true表示创建组件时立马执行一次。
watch: {
searchInputValue:{
handler: 'fetchPostList',
immediate: true
}
}
26. 父子组件通信 -- 子组件可以调用父组件的方法
- 实现思路
使用
this.$emit()
以下示例为分页组件,下面只是将主要的部分代码贴出
- 父组件
<template>
<!-- 分页 -->
<pagination @updatePageData="loadPageData"></pagination>
</template>
<script>
export default{
methods:{
loadPageData:function(){
// do something
}
}
}
<script>
- 上面代码的说明
@updatePageData="loadPageData"
:传递方法时前面使用@
;updatePageData
是给子组件使用的 父组件loadPageData
方法的别名
- 子组件
export default{
methods:{
pageGo:function(){
const me = this
// 调用父组件方法
me.$emit('updatePageData')
}
}
}
27. 父子组件通信 -- 子组件可动态获取父组件的数据
- 问题描述
由于父组件的数据是动态获取的,而子组件初始化时如果获取不到数据就
Game Over
- 实现思路
使用
props
传数据 ;watch
监听数据
以下示例为分页组件,下面只是将主要的部分代码贴出
- 父组件
<template>
<!-- 分页 -->
<pagination :parentPageData="pageGetData"></pagination>
</template>
<script>
export default{
data(){
return{
pageGetData:[]
}
},
methods:{
getData:function(){
// ajax 请求之后改变 pageGetData 的数据
}
}
}
<script>
- 上面代码的说明
:parentPageData="pageGetData"
传递方法前面使用:
;parentPageData
是给子组件使用的 父组件pageGetData
数据的别名
- 子组件
export default{
props:['parentPageData'], // 父组件数据 别名
watch:{
// 监听父组件数据变化实时更新数据
parentPageData:{
handler: 'loadPageList',
immediate: true
}
},
methods:{
// 加载页面数据
loadPageList:function(){
// do something
}
}
}
28. vue 多页面开发分页组件 有搜索功能
29. Vue
在 .vue
文件的样式 style
标签中使用 background:url()
引入图片
参考资料 vue 背景图引入
- 示例代码片段
<style scoped>
.loading {
position: fixed;
left: 0;
top: 0;
background: url('~@/assets/img/loading-ball.svg') center center no-repeat #fff;
width: 100vw;
height: 100vh;
z-index: 1000;
}
</style>
30. 页面加载数据之前增加 loading
动画
31. 封装一个 axios
的通用方法
- 思路
自定义一个函数,将其挂载到
image.pngVue
对象的prototype
上面,方便在页面使用,因为axios
一般得和qs
模块配合使用
qs 使用参考地址
- 在
main.js
文件中挂载自定义方法
import Vue from 'vue'
import 'babel-polyfill' // 解决 axios 兼容 IE 问题
import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题 -> name=hehe&age=10
import axios from 'axios'
// import router from './router'
import '@/assets/css/common.css'
import App from './index.vue'
Vue.config.productionTip = false
/**
* 自定义一个方法封装 axios 请求,并将其挂载至 Vue 原型链
* @param {string} url axios 请求的地址
* @param {string} dataJson axios 向请求地址发送的 json 数据
* @param {function} sucessFn axios 成功回调函数
* @param {function} errorFn axios 失败回调函数
*/
Vue.prototype.axiosFn = function(url, dataJson, sucessFn, errorFn) {
axios
.post(url, qs.stringify(dataJson))
.then(response => {
console.log(response)
sucessFn()
})
.catch(error => {
console.log(error)
errorFn()
})
}
/* eslint-disable no-new */
new Vue({
el: '#app',
// router,
components: { App },
template: '<App/>'
})
- 具体的使用就不写了,只需要在调用方法
axiosFn
时给其传相应的参数即可