1、vue-router 中使用 vuex
首先确保 main.js 中组合了 vuex 和 router
Vue.use(VueRouter)
Vue.use(Vuex)
new Vue({
el: '#app',
router: createVueRouter(VueRouter),
store: createVueStore(Vuex),
render: h => h(App)
})
复制代码
router.js 中可以直接使用 router.app.$options.store
let be4Each = function(router) {
router.beforeEach((to, from, next) => {
router.app.$options.store.dispatch('handleDoSomething').then((i) => {
// doSomething
next();
});
});
}
let createVueRouter = function(VueRouter) {
let router = new VueRouter(routerConfig)
be4Each(router)
afterEach(router)
return router
}
export default createVueRouter;
复制代码
2、vue组件中js定义的本地图片在页面无法显示
本地图片直接放到img标签中是可以展示的;但是通过js引入到img标签中,是无法展示的,需要通过require才能展示 assets文件夹下的图片photo.png 本地图片直接在img标签中使用
//图片可以显示
<img src="@/assets/photo.png" />
复制代码
js中的本地图片需要使用require才能显示
//图片不能显示
<img :src="pic" />
//图片可以显示
<img :src="img" />
复制代码
data( ){
return {
pic:'@/assets/photo.png',
img:require('@/assets/photo.png')
}
}
复制代码
3、vue build 过程取消 console、debugger 控制台信息输出
一、前言
Vue项目开发过程中,会经常需要使用console.log、console.info、alert等测试语句来输出内容,而在生产环境之中,我们不希望控制台同样输出以上信息,特别是用户信息相关。
打包前,逐一去删除、注释显然费时费力,好在Vue提供了通过配置文件修改配置变量,实现在开发环境打印,而生产环境不打印控制台信息的方法。
二、配置文件修改
修改build/webpack.prod.conf.js
配置文件,找到UglifyJsPlugin
配置,在compress
中添加如下代码即可。
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
// 打包的时候移除console、debugger
drop_debugger: true, // 移除debugger
drop_console: true, // 移除console
pure_funcs: ['console.log','console.info']
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
复制代码
优化配置方式如下:
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
// 打包的时候移除console、debugger
drop_debugger: process.env.NODE_ENV=== 'production', // 移除debugger
drop_console: process.env.NODE_ENV=== 'production', // 移除console
warnings: process.env.NODE_ENV=== 'production', // 移除告警信息
pure_funcs: ['console.log','console.info']
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
复制代码
其中,process.env.NODE_ENV
定义在prod.env.js
文件中,
module.exports = {
NODE_ENV: "production"
}
复制代码
prod.env.js
文件在config/index.js
的build.env
配置中引入。
build: {
env: require('./prod.env')
}
复制代码
4、vue-cli 脚手架 webpack.base.conf.js 配置文件讲解
一、前言
webpack.base.conf.js
文件是vue
开发环境和生产环境wepack
相关配置文件,主要用来处理各种文件的配置。
// 引入nodejs路径模块
var path = require('path')
// 引入utils工具模块,utils主要用来处理css-loader和vue-style-loader的
var utils = require('./utils')
// 引入config目录下的index.js配置文件,主要用来定义一些开发和生产环境的属性
var config = require('../config')
// vue-loader.conf配置文件是用来解决各种css文件的,定义了诸如css,less,sass之类的和样式有关的loader
var vueLoaderConfig = require('./vue-loader.conf')
// 此函数是用来返回当前目录的平行目录的路径,因为有个'..'
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
// 入口文件是src目录下的main.js
app: './src/main.js'
},
output: {
// 路径是config目录下的index.js中的build配置中的assetsRoot,也就是dist目录
path: config.build.assetsRoot,
// 文件名称这里使用默认的name也就是main
filename: '[name].js',
// 上线地址,也就是真正的文件引用路径,如果是production生产环境,其实这里都是 '/'
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
// resolve是webpack的内置选项,顾名思义,决定要做的事情,也就是说当使用 import "jquery",该如何去执行这件事
// 情就是resolve配置项要做的,import jQuery from "./additional/dist/js/jquery" 这样会很麻烦,可以起个别名简化操作
extensions: ['.js', '.vue', '.json'], // 省略扩展名,也就是说.js,.vue,.json文件导入可以省略后缀名,这会覆盖默认的配置,所以要省略扩展名在这里一定要写上
alias: {
//后面的$符号指精确匹配,也就是说只能使用 import vuejs from "vue" 这样的方式导入vue.esm.js文件,不能在后面跟上 vue/vue.js
'vue$': 'vue/dist/vue.esm.js',
// resolve('src') 其实在这里就是项目根目录中的src目录,使用 import somejs from "@/some.js" 就可以导入指定文件,是不是很高大上
'@': resolve('src')
}
},
// module用来解析不同的模块
module: {
rules: [
{
test: /\.(js|vue)$/,
// 也就是说,对.js和.vue文件在编译之前进行检测,检查有没有语法错误
loader: 'eslint-loader',
// 此选项指定enforce: 'pre'选项可以确保,eslint插件能够在编译之前检测,如果不添加此项,就要把这个配置项放到末尾,确保第一个执行
enforce: 'pre',
// include选项指明这些目录下的文件要被eslint-loader检测,还有一个exclude表示排除某些文件夹
include: [resolve('src'), resolve('test')],
// options表示传递给eslint-loader的参数
options: {
// formatter是参数的名称,eslint-friendly-formatter是eslint的一个报告总结插件,也就是说eslint的检测报告非常难看懂,这个插件就是整理这些报告方便查阅的
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
// 对vue文件使用vue-loader,该loader是vue单文件组件的实现核心,专门用来解析.vue文件的
loader: 'vue-loader',
// 将vueLoaderConfig当做参数传递给vue-loader,就可以解析文件中的css相关文件
options: vueLoaderConfig
},
{
test: /\.js$/,
// 对js文件使用babel-loader转码,该插件是用来解析es6等代码
loader: 'babel-loader',
// 指明src和test目录下的js文件要使用该loader
include: [resolve('src'), resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
// 对图片相关的文件使用 url-loader 插件,这个插件的作用是将一个足够小的文件生成一个64位的DataURL
// 可能有些老铁还不知道 DataURL 是啥,当一个图片足够小,为了避免单独请求可以把图片的二进制代码变成64位的
// DataURL,使用src加载,也就是把图片当成一串代码,避免请求,神不神奇??
loader: 'url-loader',
options: {
// 限制 10000 个字节一下的图片才使用DataURL
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]') // 这个函数执行结果是 /img/[name].[hash:7].[ext]
// 不知道吧 name 设置成 /img/[name].[hash:7].[ext] 意欲何为,猜测应该是输出图片的路径或者是解析图片的路径
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
// 字体文件处理,和上面一样
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
}
}
复制代码
二、注
对于文件小于10000byte,在生成的代码用中base64来替代; 大于10000byte,按[name].[hash:7].[ext]的命名方式放到static/img下面,方便做cache; 因为项目中会有动态引入而无法提前通过loader加载的图片,用CopyWebpackPlugin放到dist目录下。所以最后build完的图片资源就是两部分:一部分是dev下的整个图片文件夹(被复制了一份),另外就是经过url-loader处理过的dist/img下带hash的图片。
5、<keep-alive>
实现页面缓存
一、引入场景
官网解释:<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。 当组件在 <keep-alive>
内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。 在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 <keep-alive>
组件内的所有嵌套组件中触发。 主要用于保留组件状态或避免重新渲染
。
二、应用场景
如果未使用keep-alive组件,则在页面回退时仍然会重新渲染页面,触发created钩子,用户体验不好。 在菜单存在多级关系,多见于列表页+详情页的场景,使用keep-alive组件会显著提高用户体验,如:商品列表页点击商品跳转到商品详情,返回后仍显示原有信息,订单列表跳转到订单详情,返回,等等场景。
三、keep-alive 生命周期
初次进入时:created > mounted > activated;退出后触发 deactivated;
再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;
四、项目实践
1.更改App.vue
<div id="app" class='wrapper'>
<keep-alive>
<!-- 需要缓存的视图组件 -->
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
复制代码
2.在路由中设置keepAlive
{
path: 'list',
name: 'itemList', // 商品管理
component (resolve) {
require(['@/pages/item/list'], resolve)
},
meta: {
keepAlive: true,
title: '商品管理'
}
}
复制代码
3.更改 beforeEach钩子
这一步是为了清空无用的页面缓存。 假设现在A、B两个页面都开启的缓存:
若第一次进入A页面后退出,再次进入页面时,页面不会刷新。这和目前的业务逻辑不符。我们想要的结果是A页面前进后返回,页面保持不变,而不是退出后重新进入保持不变。
在进入过A页面后进入B页面,经过测试后发现,B页面竟然会显示A页面的缓存,尽管url已经改变。
为了解决这个问题,需要判断页面是在前进还是后退。 在beforeEach钩子添加代码:
let toDepth = to.path.split('/').length
let fromDepth = from.path.split('/').length
if (toDepth < fromDepth) {
// console.log('back...')
from.meta.keepAlive = false
to.meta.keepAlive = true
}
复制代码
五、记录页面滚动位置
keep-alive
并不会记录页面滚动位置,如需在跳转时需要记录当前的滚动位置,可在触发activated
钩子时重新定位到原有位置。 具体设计思路:
在deactivated
钩子中记录当前滚动位置,使用localStorage
:
deactivated () {
window.localStorage.setItem(this.key, JSON.stringify({
listScrollTop: this.scrollTop
}))
}
复制代码
在activated
钩子中滚动:
this.cacheData = window.localStorage.getItem(this.key) ?JSON.parse(window.localStorage.getItem(this.key)) : null
$('.sidebar-item').scrollTop(this.cacheData.listScrollTop)
复制代码
6、ES数组操作:splice() 实现数组删除、替换、增加指定元素
一、前言
注:该方法会改变原始数组。
ES6
从数组中删除指定元素
findIndex()
方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
arr.splice(arr.findIndex(item => item.id === data.id), 1)
复制代码
二、splice实现删除、替换、新增
splice(index,len,[item])
复制代码
splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值。
index:数组开始下标 len: 替换/删除的长度 item:替换的值,删除操作的话, item为空 如:
arr = ['a','b','c','d']
复制代码
删除 ---- item不设置
arr.splice(1,1) //['a','c','d'] //删除起始下标为1,长度为1的一个值,len设置的1,如果为0,则数组不变
arr.splice(1,2) //['a','d'] //删除起始下标为1,长度为2的一个值,len设置的2
复制代码
替换 ---- item为替换值
arr.splice(1,1,'ttt') //['a','ttt','c','d'] //替换起始下标为1,长度为1的一个值为'ttt',len设置的1
arr.splice(1,2,'ttt') //['a','ttt','d'] //替换起始下标为1,长度为2的两个值为'ttt',len设置的1
复制代码
添加 ---- len设置为0,item为添加值
arr.splice(1,0,'ttt') //['a','ttt','b','c','d'] //表示在下标为1处添加一项'ttt'
复制代码
7、vue实战——vue中发送AJAX请求
一、简介
1)vue本身不支持发送AJAX请求,需要使用vue-resource、axios等插件实现。
2) axios
是一个基于Promise的HTTP请求客户端,用来发送请求,也是vue2.0官方推荐的,同时不再对vue-resource进行更新和维护。 参考:GitHub上搜索axios,查看API文档
二、使用axios发送AJAX请求 1、安装axios并引入
1)npm的方式: $ npm install axios -S
2)bower的方式:$ bower install axios
3)cdn的方式:
2、基本用法 1)axios([options])
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>axios发送ajax请求基本用法</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click="send">发送ajax请求</button>
</div>
<script>
new Vue({
el:"#app",
methods:{
send(){
axios({
method:'get',
url:'user.json'
}).then(function(res){
console.log(res.data.name);
});
}
}
});
</script>
</body>
</html>
复制代码
2)axios.get(url[,options]);
传参方式:
(1)通过url传参axios(‘url?key=value&key1=val2’).then();
(2)通过params选项传参 axios(‘url’,{params:{key:value}}).then();\
3)axios.post(url,data,[options]);
axios默认发送数据时,数据格式是Request Payload,并非常用的Form Data格式, 所以参数必须要以键值对形式传递,不能以json形式传。
传参方式:
(1)自己拼接为键值对 axios.post(‘url’,‘key=value&key1=value1’).then();
(2)使用transformRequest,在请求发送前将请求数据进行转换
axios.post('url',data,{
transformRequest:[
function(data){
let params = '';
for(let index in data){
params +=index+'='+data[index]+'&';
}
return params;
}
]
}).then(function(res){
console.log(res.data)
});
复制代码
3)如果使用模块化开发,可以使用qs模块进行转换
axios本身并不支持发送跨域的请求,没有提供相应的API,作者也暂没计划在axios添加支持发送跨域请求, 所以只能使用第三方库
三、跨域请求(使用vue-resource发送跨域请求) 1、使用vue-resource发送跨域请求步骤
安装vue-resource并引入:
npm install vue-resource -S
复制代码
基本用法:
使用this.$http.jsonp(url,[ops]) 发送请求
2、基本使用演示(360搜索)
1)打开360搜索,然后输入字符’a’会有一些搜索选项自动提示,如图
2)复制链接
sug.so.360.cn/suggest?cal…
3)代码演示
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>使用vue-resource发送跨域请求</title>
<!--引入vue、vue-resource文件-->
<script src="vue.min.js"></script>
<script src="vue-resource.min.js"></script>
</head>
<body>
<div id="app">
<button @click="sendJsonp">send</button>
</div>
<script>
var vm = new Vue({
el:"#app",
methods:{
sendJsonp:function(){
this.$http.jsonp('https://sug.so.360.cn/suggest',{
params:{
word:'a'
}
}).then(function(res){
console.log(res.data);
});
}
}
});
</script>
</body>
</html>
复制代码
4)结果\
3、基本例子演示(百度搜索)
1)要求同360搜索的要求
2)复制链接 =1526436420943”>sp0.baidu.com/5a1Fazu8AA5…
3)代码演示
之前360搜索jsonp回调的参数名是callback,而百度使用的参数名为cb,所以会报错,新增
jsonp:'cb'
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>使用vue-resource发送跨域请求</title>
<!--引入vue、vue-resource文件-->
<script src="vue.min.js"></script>
<script src="vue-resource.min.js"></script>
</head>
<body>
<div id="app">
<button @click="sendJsonp">send</button>
</div>
<script>
var vm = new Vue({
el:"#app",
methods:{
sendJsonp:function(){
this.$http.jsonp('https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',{
params:{
wd:'a'
},
jsonp:'cb'
}).then(function(res){
console.log(res.data);
});
}
}
});
</script>
</body>
</html>
复制代码
4)结果
8、vue cryptoJS AES加密
1.先在vue项目中安装crypto-js
npm install crypto-js
复制代码
2.新建一个secret.js文件
//引用AES源码js
const CryptoJS = require('crypto-js');
const key = CryptoJS.enc.Utf8.parse("1234123412ABCDEF");//十六位十六进制数作为密钥
const iv = CryptoJS.enc.Utf8.parse('ABCDEF1234123412');//十六位十六进制数作为密钥偏移量
//解密方法
function Decrypt(word) {
//先将Base64还原一下,因为加密的时候做了一些字符的替换
const restoreBase64 = word.replace(/\-g/,'+').replace(/_/,'/');
//返回的是解密后的对象
let decrypt = CryptoJS.AES.decrypt(restoreBase64,key,{
iv:iv,
mode:CryptoJS.mode.CBC,
padding:CryptoJS.pad.Pkcs7
});
//将解密对象转换成UTF8的字符串
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
//返回解密结果
return decryptedStr.toString();
}
//加密方法
function Encrypt(word){
console.log('组件里的:',word);
let srcs = CryptoJS.enc.Utf8.parse(word);
//CipherOption,加密的一些选项:
//mode:加密模式,可取值(CBC,CFB,CTR,CTRGladman,OFB,ECB),都在CryptoJS.mode对象下
//padding:填充方式,可取值(Pkcs7,Ansix923,Iso10126,ZeroPadding,NoPadding),都在CryptoJS.pad对象下
//iv:偏移量,mode===ECB时,不需要iv
//返回的是一个加密对象
let encrypted = CryptoJS.AES.encrypt(srcs,key,{
iv:iv,
mode:CryptoJS.mode.CBC,
padding:CryptoJS.pad.Pkcs7
});
//将结果进行base64加密
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
// export {Decrypt,Encrypt}
export {Encrypt}
复制代码
3.vue页面内容
import {Encrypt} from "../../utils/secret";
var userName = Encrypt(this.userName)//加密用户名
var userPassword = Encrypt(this.password)//加密用户密码
console.log('加密后:',userName)
console.log('加密后:',userPassword)
复制代码
9、vue axios.post请求后端接收不到参数问题
处理方案一:请求拦截
// post请求后台无法获取传递参数
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';//配置请求头
axios.defaults.transformRequest = function (data) {
return qs.stringify(data, {arrayFormat: 'brackets'})
}
复制代码
处理方案二:
//axios
axios({
method: "post",
url: host + '/xpg/baoxian/getSpbxList',
data: urlstringify({
"fl": title.trim(),
"page": 1,
"size": 10
}),
headers: {
"Content-Type": 'application/x-www-form-urlencoded'
}
})
.then(function (response) {
}
.catch(function (error) {
console.log(error);
});
//转义方法
function urlstringify(obj) {//字符串序列化
var str = '';
for (let key in obj) {
if (Object.prototype.toString.call(obj[key]) === '[object Array]' || obj[key].constructor === Object) {
//数组,对象
for (var arrKey in obj[key]) {
if (Object.prototype.toString.call(obj[key][arrKey]) === '[object Array]' || obj[key][arrKey].constructor === Object) {
//数组,对象
for (var arrarrKey in obj[key][arrKey]) {
str += '&' + key + '[' + arrKey + '][' + arrarrKey + ']=' + obj[key][arrKey][arrarrKey];
}
} else {
//普通
str += '&' + key + '[' + arrKey + ']=' + obj[key][arrKey];
}
}
} else {
//普通
str += '&' + key + '=' + obj[key];
}
}
return str.substring(1);
}
复制代码
11、vue中如何实现中英或多语言切换(含element-ui)
1、首先使用cmd窗口安装 vue-i18n 包
npm install vue-i18n --save-dev
复制代码
2、然后在main.js中引入
import VueI18n from 'vue-i18n' //导入包
//导入locales js
import i18n from './common/locales/index.js'
new Vue({
i18n,
el: '#app',
render: h => h(App)
})
复制代码
3、index.js en.js内容:
4、locales js:
import Vue from 'vue' // 引入vue实例
import VueI18n from 'vue-i18n' // 引入vue-i18n多语言包
// element ui国际化
import ElementUI from 'element-ui'
import enLocale from 'element-ui/lib/locale/lang/en'
import twLocale from 'element-ui/lib/locale/lang/zh-tw'
import idLocale from 'element-ui/lib/locale/lang/en'
import jpLocale from 'element-ui/lib/locale/lang/en'
// import idLocale from 'element-ui/lib/locale/lang/id-ID'
import ElementUILocale from 'element-ui/lib/locale'
Vue.use(VueI18n) // vue使用vue-i18n
//element ui国际化
Vue.use(ElementUI,{ElementUILocale})
const DEFAULT_LANG = 'en' // 默认语言为英文
const LOCALE_KEY = 'localeOld_block_chain' // localStorage来存放的key,名字随便定,接下来会用到。
const locales = { // 引入zh.js以及en.js
tw: require('../i18n/zh-tw.js'),
en: require('../i18n/en.js'),
id: require('../i18n/id-ID.js'),
jp: require('../i18n/jp-JP.js')
}
const i18n = new VueI18n({ // 创建带有选项的 VueI18n 实例
locale: DEFAULT_LANG, // 语言标识,在这里默认为en,即为英文
messages: locales // 语言包,上边创建的json文件
})
// element ui国际化
const UIlocales = {
tw: twLocale,
en: enLocale,
id: idLocale,
jp: jpLocale,
}
const setUIlocales = lang => {
switch (lang) {
case 'tw':
return UIlocales.tw
case 'en':
return UIlocales.en
case 'id':
return UIlocales.id
case 'jp':
return UIlocales.jp
}
}
export const setup = lang => { //切换语言的函数,lang为语言标识,en或者tw
// 在此判断lang的值,如果未定义,则让lang默认为DEFAULT_LANG,目的是为了让用户在未选择语言的时候默认为英文。
if (lang == undefined) {
lang = window.localStorage.getItem(LOCALE_KEY)
if (locales[lang] == undefined) {
lang = DEFAULT_LANG
}
} // 若lang有值,那么存入localStorage中,key为LOCALE_KEY,value为lang。
window.localStorage.setItem(LOCALE_KEY, lang)
Object.keys(locales).forEach(item => {
document.body.classList.remove('lang-${item}')
})
document.body.classList.add('lang-${lang}')
document.body.setAttribute('lang', lang)
Vue.config.lang = lang
i18n.locale = lang
// element ui 切换语言
ElementUILocale.use(setUIlocales(lang))
// 挂载需要用到多语言的js文件
const vueInstance = new Vue({ i18n });
if(vueInstance&&vueInstance.$i18n&&vueInstance.$i18n.messages){
// console.log("Vue",vueInstance)
let tipsJs = vueInstance.$i18n.messages[lang];
// console.log("tipsJs",tipsJs.lang.tipsJs)
Vue.prototype.$tipsJs = tipsJs.lang.tipsJs;
}
}
setup()
export default i18n
复制代码
5、页面使用多语言 js引入this.$t('')
template使用{{i18n.Markets}}
<div class="container_nav">
<p class="tac white fs16">{{i18n.Markets}}</p>
</div>
复制代码
computed: {
i18n() {
return this.$t('lang.markets')
},
},
复制代码
6、自定义js引入i18n
// 引入多语言
import i18n from '../common/locales/index.js';
let envIndex = i18n.t('lang').envIndex;
复制代码
13、详解vue 路由跳转四种方式 (带参数)
1. router-link
- 不带参数
<router-link :to="{name:'home'}">
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
复制代码
2.带参数(建议query传参数,不用配置路由
)
<router-link :to="{name:'home', params: {id:1}}">
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id"
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
<router-link :to="{name:'home', query: {id:1}}">
// query传参数 (类似get,url后面会显示参数)
// 路由可不配置
// html 取参 $route.query.id
// script 取参 this.$route.query.id
复制代码
2. this.$router.push() (函数里面调用)
1. 不带参数
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
2. query传参
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
// html 取参 $route.query.id
// script 取参 this.$route.query.id
3. params传参
this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
4. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
复制代码
3. this.$router.replace() (用法同上,push)
4. this.$router.go(n)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
ps : 区别
this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
14、vue前进刷新,后退不刷新and按需刷新
1.在路由文件router.js
中为目标列表页设置meta参数,里面包含keepAlive和ifDoFresh字段
{
path:'*',
name:'datalist',
component: resolve => require(['@/view/datalist'], resolve),
meta:{
keepAlive: true,
ifDoFresh:false
}
},
复制代码
2.在程序主入口main.vue
中设置页面根据keepAlive字段判断是否使用keep-alive组件。
<div class="main">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
</div>
复制代码
3.在目标列表页的beforeRouteEnter方法中判断页面进入方式(详情页,编辑页或其他方式),根据需求将路由参数的ifDoFresh字段设为true/false,
在页面的activated(开启了 keepAlive: true的页面在第二次进入时是无法触发mounted发法的)方法中根据ifDoFresh字段判断是否刷新页面
beforeRouteEnter (to, from, next) {
if(from.name!='详情页'&&from.name!='编辑页'){
to.meta.ifDoFresh = true;
}
next();
},
activated(){
//开启了keepAlive:true后再次进入,以前的搜索条件和页数都不会变,无论什么情况都调用一下获取数据的接口,这样就能得到当前搜索条件和页数的最新数据
if(this.$route.meta.ifDoFresh){
//重置ifDoFresh
this.$route.meta.ifDoFresh = false;
//获取列表数据方法第一参数为是否重置搜索条件和页数 this.getData(true);
}else{
this.getData();
}
}
复制代码
15、vue项目添加发布路径
项目模板
我的项目是使用vue init webpack
创建的,所以我需要修改3个文件。
修改文件
(1)index.html
head中添加<meta base="/macth/">
(2)路由文件添加base:'/match/'
let router = new Router({
base:'/match/,
routes: [
{
path: '/login',
type: 'login',
component: Login,
meta:{
keepAlive: true,
ifDoFresh:true,
}
},
]
});
复制代码
(3)配置文件/config/index.js 修改assetsPublicPath参数
assetsPublicPath: '/macth/',
复制代码
总结:打包修改assetsPublicPath
也可满足,后台上传不同地址即可。
16、 es6新增语法之${}
1、反单引号怎么打出来?
将输入法调整为英文输入法,单击键盘上数字键1左边的按键。
2、用法
step1: 定义需要拼接进去的字符串变量
step2: 将字符串变量用${}包起来,再写到需要拼接的地方
3、示例代码:
let a='Karry Wang';
let str=`I love ${a}, because he is handsome.`;
//注意:这行代码是用返单号引起来的
alert(str);
复制代码
一定是用反单引号啊!不要写成单引号了!!
17、Form 表单重置失败问题解决
一、前言 在Vue项目开发过程中,应用this.refs[name].resetFields();实现表单搜索元素重置时发现失效。经检查发现是form−item绑定的属性prop与包裹元素el−input绑定值不一致造成的。现梳理有关应用this.refs[name].resetFields();实现表单搜索元素重置时发现失效。经检查发现是form-item绑定的属性prop与包裹元素el-input绑定值不一致造成的。现梳理有关应用this.refs[name].resetFields();实现表单搜索元素重置时发现失效。经检查发现是form−item绑定的属性prop与包裹元素el−input绑定值不一致造成的。现梳理有关应用this.refs[name].resetFields();重置表单注意事项。
Form必须要有ref属性;
Form必须绑定:model;
<Form ref="submitUser" :model="submitUser">
复制代码
Form
的FormItem
中必须要有prop
属性;
<FormItem prop="realName">
</FormItem>
复制代码
Form
包裹的元素绑定值需与FormItem
中prop
属性名称保持一致(可类比Form
表单校验规则)
<Form ref="submitUser" :model="submitUser">
<FormItem prop="uname">
<Input type="text" v-model="submitUser.uname" placeholder="用户名"></Input>
</FormItem>
<FormItem prop="passwd">
<Input type="text" v-model="submitUser.passwd" placeholder="密码"></Input>
</FormItem>
<FormItem>
<Button type="info" @click="query">Login</Button>
<Button @click="handleReset('submitUser')" style="margin-left: 8px;" type="info">Reset</Button>
</FormItem>
</Form>
<script>
export default {
data () {
return {
submitUser:{
realName:'',
identityNumber:'',
mobileNumber:'',
telePhoneNumber:''
}
}
},
methods:{
handleReset (name) {
this.$refs[name].resetFields();
}
}
}
</script>
复制代码
18、Vue监听数据变化
监听数据变化,在Vue中是通过侦听器来实现的,时刻监听某个数据的变化
watch的基本用法
- 侦听器的书写位置
写在export default中与data和methods用,隔开
<script>
export default {
name: "app",
// 数据 key---data value---Function
data: function () {
return {
count: 1
};
},
// 方法 key---methods value---{}
methods: {},
//在export default中添加即可不用管顺序
watch: {
//监听内容
count() {
console.log("count发生了变化");
}
}
};
</script>
复制代码
监听器里的方法一定要与被监听的变量名一致
侦听器的进阶用法
获取前一次的值
有的时候需要上一次的数据,再上一个案例中添加一个参数即可获取旧值
watch:{
inputValue(value,oldValue) {
// 第一个参数为新值,第二个参数为旧值,不能调换顺序
console.log(`新值:${value}`);
console.log(`旧值:${oldValue}`);
}
}
复制代码
handler方法
和immediate属性
immediate: 可以让页面第一次渲染的时候去触发侦听器
handler: 监听到修改之后这个函数会执行
侦听器实际上是一个对象,里面包含了handler方法和其他属性:
<script>
export default {
name: "app",
watch: {
firstName: {
handler: function (newName, oldName) {
this.fullName = newName + " " + this.lastName;
},
immediate: true
}
}
};
</script>
复制代码
19、vue中页面加载进度条效果
滚动条效果插件:nprogress
- 安装:
cnpm install --save nprogress
复制代码
- main.js中引入:
//引入nprogressimport NProgress from 'nprogress'import 'nprogress/nprogress.css' //这个样式必须引入
复制代码
- main.js中进行一些配置:
NProgress.configure({
easing: 'ease', // 动画方式
speed: 500, // 递增进度条的速度
showSpinner: false, // 是否显示加载ico
trickleSpeed: 200, // 自动递增间隔
minimum: 0.3 // 初始化时的最小百分比
})
复制代码
- 接下来,还是在mian.js中,
router.beforeEach((to, from , next) => {
// 每次切换页面时,调用进度条
NProgress.start();
// 这个一定要加,没有next()页面不会跳转的。这部分还不清楚的去翻一下官网就明白了
next();
});
复制代码
router.afterEach(() => {
// 在即将进入新的页面组件前,关闭掉进度条
NProgress.done()
})
复制代码
20、 webpack only one instance of babel-polyfill is allowe
旧的浏览器不兼容babel-polyfill
项目是用vue-cli2搭建的,主要引起错误的原因如下图所示:
用了这种方式后,babel-polyfill与其他的插件造成了冲突,也就是说有两个地方都用到了babel-polyfill
于是我的解决方案如下所示:
第一步去掉配置文件的babel-polyfill
entry: {
app: './src/main.js',
}
复制代码
第二步,在main.js加上以下代码
if (!global._babelPolyfill) {
require('babel-polyfill');
}
复制代码
21、nvm常用命令 切换node
常用命令:
nvm ls :列出所有已安装的 node 版本
nvm ls-remote :列出所有远程服务器的版本(官方node version list)
nvm list :列出所有已安装的 node 版本
nvm list available :显示所有可下载的版本
nvm install stable :安装最新版 node
nvm install [node版本号] :安装指定版本 node
nvm uninstall [node版本号] :删除已安装的指定版本
nvm use [node版本号] :切换到指定版本 node
nvm current :当前 node 版本
nvm alias [别名] [node版本号] :给不同的版本号添加别名
nvm unalias [别名] :删除已定义的别名
nvm alias default [node版本号] :设置默认版本
复制代码
22、前端脚手架并发布到npm
- 首先在本地创建一个npm项目。
- 在本地新建文件夹。vue-test
- 创建好文件夹后,使用cmd进入该创建好的文件夹。
- 使用npm init 全部Y 生成一个默认的package.json模板,在package.json 中需要增加一个bin配置,声明这个bin的名称以及对应文件地址。
- 在当前文件夹下新建一个文件夹目录bin目录。
- 在新建的这个bin目录下新建一个index.js文件。
- 编辑这个index.js 文件,在文件中添加 console.log("vue-test")
- 并且在当前文件的首开始,添加一行 #!/usr/bin/env node
- 将脚手架发布到npm(此处需要大家先行在npm进行注册。) 使用npm login 进行npm登陆。 然后使用 npm publish 发布 (此处报错,建议百度。一般都是名称重复问题)
- 推送成功后,在自己电脑本地则可以使用 npm install vue-test -g 进行安装
- 安装完成后,则可以使用 vue-test (package.json 中bin配置的那个名称)来进行验证
23、 vue 刷新不出现白屏的解决办法
1、路由切换操作
// 如果在这个空间有权限,刷新当前页面
this.$router.push(path).catch(err => err);
复制代码
2、在使用router-view 的地方(一般在APP.vue
文件)
<template>
<div class="home">
<router-view class="right" v-if="isRouterAlive" />
</div>
</template>
<script>
export default {
provide() {
return {
reload: this.reload
}
},
data() {
return {
isRouterAlive: true
};
},
mounted() {
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(() => {
this.isRouterAlive = true
})
}
}
};
</script>
复制代码
3、在被刷新的地方
方式一:watch监听
export default {
inject: ['reload'],
watch: {
// 监听到路由跳转时,强制刷新
'$route': {
handler() {
this.reload()
}
}
},
}
复制代码
方式二,methods方法调用刷新
export default {
inject: ['reload'],
created() {
this.refresh();
},
methods: {
//刷新方法
refresh(){
this.reload()
}
},
}
复制代码
24、 vue-resource和axios和vue-axios区别
vue-resource(已经淘汰)
目前主流的 Vue 项目,都选择 axios 来完成 ajax 请求,基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 Node.js 中使用。
vue-axios 是在axios基础上扩展的插件,在Vue.prototype原型上扩展了$http等属性,可以更加方便的使用axios,使用vue-axios更多是为了符合规范,并且方便协作吧。
总结:
25、window.open在Safari中不能打开的问题
1.原因分析:
原因:大部分现代的浏览器(Chrome/Firefox/IE 10+/Safari)都默认开启了阻止弹出窗口的策略,原因是window.open被广告商滥用,严重影响用户的使用。这个阻止弹出窗口的操作,并不是直接封杀window.open(),而是会根据用户的行为来判断这次window.open()是否属于流氓操作。
如果是由用户触发的动作所引起的 window.open 就不会被浏览器所阻止,比如写在 onclick 这些事件 handler 里的,但如果是代码自己触发的就会被阻止。
那么,我们可以知道,在Safari中无法open新窗口,原因是Safari的安全机制将其阻挡。
并不是所有地方都无法正常使用,在一些ajax或者jquery的getjson等回调代码中只要调用window.open都失效。原因是苹果的安全策略拦截。
2.解决方案:
解决办法有4种:
(1)用window.location.replace()来替代,【或者改变location.href,可以解决,缺点就是不是新开的窗口】
(2)苹果系统设置,偏好设置->安全性,去掉阻止弹窗的复选框就ok了。 【不建议,会改变用户的设置】
(3)在回到函数中生成一个链接,让用户再次点击下,因为链接是无论如何不会被拦截的。【不建议,多加了一个动作】
(4)在回调代码之前打开一个空窗口,例如 var w=window.open(xxx); 然后在回调函数中设置它的location。【推荐】
例如w.location='juejin.cn/user/229183…'; 具体分析和代码参考:
var openWin = function(){
var winRef = window.open("url","_blank");
$.ajax({
type: '',
url: '',
data: '',
......
success:function(json){
winRef.location = "新的url";
}
});
};
复制代码
26、解决Vuex-在F5刷新页面后数据不见
1.问题场景
vuex优势:相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到。 vuex劣势:在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。 为了克服这个问题, vuex-persistedstate出现了
2.原理
- 将vuex的state存在localStorage或sessionStorage或cookie中一份
- 刷新页面的一瞬间,vuex数据消失,vuex会去sessionStorage中拿回数据,变相的实现了数据刷新不丢失~
3.使用方法
- 安装
npm install vuex-persistedstate --save
复制代码
-
在store下的index.js中,引入并配置
import createPersistedState from "vuex-persistedstate" const store = new Vuex.Store({ // ... plugins: [createPersistedState()] }) 复制代码
-
此时可以选择数据存储的位置,可以是localStorage/sessionStorage/cookie,此处以存储到sessionStorage为例,配置如下:
import createPersistedState from "vuex-persistedstate" const store = new Vuex.Store({ // ... plugins: [createPersistedState({ storage: window.sessionStorage })] }) 复制代码
4. 存储指定state:
vuex-persistedstate默认持久化所有state,指定需要持久化的state,配置如下:
import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
// ...
plugins: [createPersistedState({
storage: window.sessionStorage,
reducer(val) {
return {
// 只储存state中的user
user: val.user
}
}
})]
复制代码
5. 如果此刻想配置多个选项,将plugins写成一个一维数组,不然会报错。
import createPersistedState from "vuex-persistedstate"
import createLogger from 'vuex/dist/logger'
// 判断环境 vuex提示生产环境中不使用
const debug = process.env.NODE_ENV !== 'production'
const createPersisted = createPersistedState({
storage: window.sessionStorage
})
export default new Vuex.Store({
// ...
plugins: debug ? [createLogger(), createPersisted] : [createPersisted]
})
复制代码
27、vue实现滚动公告栏效果组件
<template>
<div>
<div class="textBox">
<transition name="slide">
<p class="text" :key="text.id">
<el-tag type="warning">{{text.val.tag}}</el-tag>
{{text.val.title}}</p>
</transition>
</div>
</div>
</template>
<script>
export default {
name: 'scroll',
data () {
return {
textArr: [
{tag:'精彩推荐',title:'第1条公告'},
{tag:'热门推荐',title:'第3条公告'},
{tag:'精彩推荐',title:'第3条公告'},
{tag:'公司公告',title:'第4条公告'},
{tag:'热门推荐',title:'第5条公告'},
],
number: 0
}
},
computed: {
text () {
return {
id: this.number,
val: this.textArr[this.number]
}
}
},
mounted () {
this.startMove()
},
methods: {
startMove () {
// eslint-disable-next-line
let timer = setTimeout(() => {
if (this.number === this.textArr.length) {
this.number = 0;
} else {
this.number += 1;
}
this.startMove();
}, 2500); // 滚动不需要停顿则将2000改成动画持续时间
}
}
}
</script>
<style scoped>
.textBox {
width: 100%;
height: 40px;
margin: 0 auto;
overflow: hidden;
position: relative;
text-align: center;
}
.text {
width: 100%;
position: absolute;
bottom: 0;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.5s linear;
}
.slide-enter{
transform: translateY(20px) scale(1);
opacity: 1;
}
.slide-leave-to {
transform: translateY(-20px) scale(0.8);
opacity: 0;
}
</style>
复制代码
28、解决input只能输入金额类型的方案(金额输入框只能输入2位小数)
<input type="digit" v-model="writeMoney" class="payInput" @input="oninput" :maxlength="moneyMaxLeng" />
data() {
return {
writeMoney: "",
moneyMaxLeng: 8//规定最大可输入的长度
}
},
//输入内容验证
oninput(e) {
this.$nextTick(() => {
let val = e.target.value.toString();
val = val.replace(/[^\d.]/g, ""); //清除"数字"和"."以外的字符
val = val.replace(/.{2,}/g, "."); //只保留第一个. 清除多余的
val = val.replace(/^0+./g, '0.');
val = val.match(/^0+[1-9]+/) ? val = val.replace(/^0+/g, '') : val
val = (val.match(/^\d*(.?\d{0,2})/g)[0]) || ''
if (val.includes(".")) {
let numDian = val.toString().split(".")[1].length;
if (numDian === 2) {
this.moneyMaxLeng = val.length;
}
} else {
this.moneyMaxLeng = 8;
}
this.writeMoney = val;
});
},
复制代码
29、Vue中使用transform的translateX来实现下滑线跟随导航。
1、template中的代码
<ul class="tab" :style="{height: tabheight}">
<li
ref="iWidth"
v-for="(item,index) in tabList"
:key="index"
:class="{'on': checkindex == index}"
@click="checkli(index)"
>{{item}}</li>
<i :style="{transform:`translateX(${iWidths/2+checkindex*iWidths}px) translateX(-50%)`}"></i>
</ul>
复制代码
2、css
ul.tab {
height: 1000px;
width: 100%;
border-bottom: 1px solid #eeeeee;
line-height: 1rem;
font-size: 0.32rem;
color: #333333;
display: flex;
position: relative;
overflow: hidden;
transition: all 0.5s;
}
.tab li {
flex: 1;
text-align: center;
transition: all 0.5s;
}
.tab li.on {
color: #da0428;
}
.tab i {
width: 0.6rem;
height: 0.05rem;
border-radius: 0.03rem;
background: #da0428;
bottom: 0;
position: absolute;
transition: all 0.5s;
}
复制代码