首先确保 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;
- 复制代码
本地图片直接放到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')
- }
- }
- 复制代码
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')
- }
- 复制代码
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的图片。
实现页面缓存官网解释: 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似, 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。 当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。 在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 组件内的所有嵌套组件中触发。 主要用于保留组件状态或避免重新渲染。
如果未使用keep-alive组件,则在页面回退时仍然会重新渲染页面,触发created钩子,用户体验不好。 在菜单存在多级关系,多见于列表页+详情页的场景,使用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)
- 复制代码
注:该方法会改变原始数组。
ES6从数组中删除指定元素
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
- arr.splice(arr.findIndex(item => item.id === data.id), 1)
- 复制代码
- 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'
- 复制代码
一、简介
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)结果

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)
- 复制代码
- // 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);
- }
- 复制代码
- npm install vue-i18n --save-dev
- 复制代码
- import VueI18n from 'vue-i18n' //导入包
- //导入locales js
- import i18n from './common/locales/index.js'
-
- new Vue({
- i18n,
- el: '#app',
- render: h => h(App)
- })
- 复制代码


- 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
- 复制代码
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')
- },
- },
- 复制代码
- // 引入多语言
- import i18n from '../common/locales/index.js';
- let envIndex = i18n.t('lang').envIndex;
- 复制代码

- <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
- 复制代码
- 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 会消失
-
- 复制代码
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
ps : 区别
this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
router.js中为目标列表页设置meta参数,里面包含keepAlive和ifDoFresh字段- {
- path:'*',
- name:'datalist',
- component: resolve => require(['@/view/datalist'], resolve),
- meta:{
- keepAlive: true,
- ifDoFresh:false
- }
- },
- 复制代码
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>
- 复制代码
在页面的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();
- }
- }
- 复制代码
我的项目是使用vue init webpack创建的,所以我需要修改3个文件。
head中添加

base:'/match/'- let router = new Router({
- base:'/match/,
- routes: [
- {
- path: '/login',
- type: 'login',
- component: Login,
- meta:{
- keepAlive: true,
- ifDoFresh:true,
- }
- },
- ]
- });
- 复制代码

- assetsPublicPath: '/macth/',
- 复制代码

总结:打包修改assetsPublicPath也可满足,后台上传不同地址即可。
${}1、反单引号怎么打出来?
将输入法调整为英文输入法,单击键盘上数字键1左边的按键。
2、用法
step1: 定义需要拼接进去的字符串变量
step2: 将字符串变量用${}包起来,再写到需要拼接的地方
3、示例代码:
- let a='Karry Wang';
-
- let str=`I love ${a}, because he is handsome.`;
- //注意:这行代码是用返单号引起来的
-
- alert(str);
- 复制代码
一定是用反单引号啊!不要写成单引号了!!
一、前言 在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>
- 复制代码
监听数据变化,在Vue中是通过侦听器来实现的,时刻监听某个数据的变化
- <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>
- 复制代码
滚动条效果插件:nprogress
- cnpm install --save nprogress
- 复制代码
- //引入nprogressimport NProgress from 'nprogress'import 'nprogress/nprogress.css' //这个样式必须引入
- 复制代码
- NProgress.configure({
- easing: 'ease', // 动画方式
- speed: 500, // 递增进度条的速度
- showSpinner: false, // 是否显示加载ico
- trickleSpeed: 200, // 自动递增间隔
- minimum: 0.3 // 初始化时的最小百分比
- })
- 复制代码
- router.beforeEach((to, from , next) => {
- // 每次切换页面时,调用进度条
- NProgress.start();
- // 这个一定要加,没有next()页面不会跳转的。这部分还不清楚的去翻一下官网就明白了
- next();
- });
- 复制代码
- router.afterEach(() => {
- // 在即将进入新的页面组件前,关闭掉进度条
- NProgress.done()
- })
- 复制代码
旧的浏览器不兼容babel-polyfill

项目是用vue-cli2搭建的,主要引起错误的原因如下图所示:

用了这种方式后,babel-polyfill与其他的插件造成了冲突,也就是说有两个地方都用到了babel-polyfill
于是我的解决方案如下所示:
- entry: {
- app: './src/main.js',
- }
- 复制代码
- if (!global._babelPolyfill) {
- require('babel-polyfill');
- }
- 复制代码
常用命令:
-
- 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版本号] :设置默认版本
-
- 复制代码
- 首先在本地创建一个npm项目。
- 在本地新建文件夹。vue-test
- 创建好文件夹后,使用cmd进入该创建好的文件夹。
- 使用npm init 全部Y 生成一个默认的package.json模板,在package.json 中需要增加一个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配置的那个名称)来进行验证
- // 如果在这个空间有权限,刷新当前页面
- this.$router.push(path).catch(err => err);
- 复制代码
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>
- 复制代码
方式一:watch监听
- export default {
- inject: ['reload'],
- watch: {
- // 监听到路由跳转时,强制刷新
- '$route': {
- handler() {
- this.reload()
- }
- }
- },
- }
- 复制代码
方式二,methods方法调用刷新
- export default {
- inject: ['reload'],
- created() {
- this.refresh();
- },
- methods: {
- //刷新方法
- refresh(){
- this.reload()
- }
- },
- }
- 复制代码
vue-resource(已经淘汰)
目前主流的 Vue 项目,都选择 axios 来完成 ajax 请求,基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 Node.js 中使用。
vue-axios 是在axios基础上扩展的插件,在Vue.prototype原型上扩展了$http等属性,可以更加方便的使用axios,使用vue-axios更多是为了符合规范,并且方便协作吧。

总结:

原因:大部分现代的浏览器(Chrome/Firefox/IE 10+/Safari)都默认开启了阻止弹出窗口的策略,原因是window.open被广告商滥用,严重影响用户的使用。这个阻止弹出窗口的操作,并不是直接封杀window.open(),而是会根据用户的行为来判断这次window.open()是否属于流氓操作。
如果是由用户触发的动作所引起的 window.open 就不会被浏览器所阻止,比如写在 onclick 这些事件 handler 里的,但如果是代码自己触发的就会被阻止。
那么,我们可以知道,在Safari中无法open新窗口,原因是Safari的安全机制将其阻挡。
并不是所有地方都无法正常使用,在一些ajax或者jquery的getjson等回调代码中只要调用window.open都失效。原因是苹果的安全策略拦截。
解决办法有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";
- }
- });
- };
- 复制代码
vuex优势:相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到。 vuex劣势:在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。 为了克服这个问题, vuex-persistedstate出现了
- 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
- })]
- })
- 复制代码
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
- }
- }
- })]
- 复制代码
- 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]
- })
- 复制代码
- <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>
- 复制代码
- <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;
- });
- },
- 复制代码
- <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>
- 复制代码
- 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;
- }
- 复制代码