VUE杂谈

我没系统学过VUE和element-ui,都是要用了再官网上查找,或者百度

1、element中调用方法

再普通vue中调用方法是标签中写@click="方法名",然后再在方法中vue实例中

methods:{
      方法名(){
        alert("123");
        //code...
      }
    }

但是在element-ui元素中,要 @click.native=方法名",调用的一样

实例

<template>
   <el-pagination
           background
           layout="prev, pager, next"
           :total="1000"
           @click.native="showSome">
   </el-pagination>
</template>

<script>
  export default {
    methods:{
      showSome(){
        alert("")
      }
    }
  };
</script>

在这里插入图片描述

2、有些element自带事件和参数

还是上面那个例子,打开官网往下走,看到
在这里插入图片描述
这个current-page参数就是页数,那么事件往下面翻

在这里插入图片描述

看到,current-page改变时,事件名为current-change,并且有个回调参数为当前页,那么

<el-pagination
       background
       layout="prev, pager, next"
       :total="1000"
       @current-change="page">
</el-pagination>

<script>
  export default {
    methods:{
      page(currPage){
          alert(currPage)
      }
    }
  };
</script>
  • 调用方法,不是@click而是 @current-change,因为上面也说了事件是这个。。然后这个事件,定义个方法名吧,就叫page,在下面写方法page,其有个回调参数,参数名就自己瞎写了,就可以用到了

在这里插入图片描述

3、分页功能

使用分页功能的时候,其有个属性为page-size(每页显示条目个数),这个记得设置,不然默认是10 ,然后:total是(总数目),这个也要记得设置,然后页数就是:total/page-size

4、axios得get与post

5、跳转并且传值

就是点击一个按钮,路由改变,并且传递参数
其跳转传值有:<router-link>直接传值跳转 和 方法内的this.$route.push(query:{})
接受值有2中方法,是params和query接受
所以是2*2=4种跳转传值方法

1)router-link + params

路由:

{
	  path:'/test',
	  name:'Test',
	  component:Test
  },{
  		//占位符
	  path:'/test/:id',
	  name:'Test2',
	  component:Test2
  }
<!-- test -->
<template>
	<div>
		我是test1
		<!-- 1、直接通过 router-link 加上地址传值,id就是用到占位符了-->
		<router-link :to="'/test/'+id">点我跳转</router-link>
	</div>
</template>

<script>
	export default {
		name: "Test",
		data() {
			return {
				id:123
			}
		}
	}
</script>
<!-- test2 -->
<template>
	<div>
		我是跳转的
		<h2>{{id}}</h2>
		<h2>{{this.$route.params.id}}</h2>
    </div>
</template>

<script>
	export default {
		computed:{
			id(){
				//从路由中的占位符拿到数据
				return this.$route.params.id
			}
		}
	}
</script>

这是用computed方式的,用created来接受然后赋值也是可以的
在这里插入图片描述

在这里插入图片描述

2)router-link + query

这个就不要用到路由注册表了,用一般的就行

{
	  path:'/test',
	  name:'Test',
	  component:Test
  },{
	  path:'/test2',
	  name:'Test2',
	  component:Test2
  }
<!-- test -->
<template>
	<div>
		我是test1
		<!-- 一样是 :to ,但是又path和query,query传对象的 -->
		<router-link 
		:to="{	
			path:'/test2',
			query:this.person}">
		点我跳转</router-link>

	</div>

</template>

<script>

	export default {
		name: "Test",
		data() {
			return {
				person:{
					name:'lihua',
					id:666
				}
			}
		}
	}
</script>
<!-- test2 -->
<template>
	<div>
		我是跳转的
		<h2>name:{{person.name}}</h2>
		<h2>id:{{person.id}}</h2>
		<h2>{{this.$route.query}}</h2>
    </div>
</template>

<script>
	export default {
		computed:{
			person(){
				//用this.$route.query来接受刚才传过来的值
				return this.$route.query
			}
		}
	}
</script>>

在这里插入图片描述

3)$router.push + params

这个还是要占位符的

{
	  path:'/test',
	  name:'Test',
	  component:Test
  },{
  		//占位符
	  path:'/test/:id',
	  name:'Test2',
	  component:Test2
  }
<!-- test -->
<template>
	<div>
		我是test1
		<!-- 1、用点击事件去完成-->
		<button @click="tourl">点我跳转</button>
	</div>
</template>

<script>

	export default {
		name: "Test",
		data() {
			return {
				id:666
			}
		},
		methods: {
			tourl(){
				//点击事件,就传送到xxx + id
				this.$router.push('/test/'+this.id)
			}
		}
	}
</script>
<!-- test2 -->
<template>
	<div>
		我是跳转的
		<h2>{{id}}</h2>
		<h2>{{this.$route.params.id}}</h2>
	</div>
</template>

<script>
	export default {
		computed: {
			id() {
				//从路由中的占位符拿到数据
				return this.$route.params.id
			}
		}
	}
</script>

4)$router.push + query

{
	  path:'/test',
	  name:'Test',
	  component:Test
  },{
	  path:'/test2',
	  name:'Test2',
	  component:Test2
  }
<!-- test -->
<template>
	<div>
		我是test1
		<button @click="tourl">点我跳转</button>

	</div>

</template>

<script>
	export default {
		name: "Test",
		data() {
			return {
				person:{
					name:'lihua',
					id:666
				},
			}
		},
		methods: {
			tourl(){
				this.$router.push({
					//一样又path和query,然后那边就query接受
					path:'/test2',
					query:this.person
				})
			}
		},
	}
</script>
<!-- test2 -->
<template>
	<div>
		我是跳转的
		<h2>name:{{person.name}}</h2>
		<h2>id:{{person.id}}</h2>
		<h2>{{this.$route.query}}</h2>
	</div>
</template>

<script>
	export default {
		computed: {
			person() {
				return this.$route.query
			},
		}
	}
</script>

5)总结

总的来说,query是接受对象,params接受一个key的。
router-link用来做a标签的简单跳转,$router.push用在方法里面更灵活
params需要路由占位符,query不需要

5.5、跳转和传值(笔记太垃圾已废弃,具体看5)

1、this.$router.push(“xxx”)

在方法中使用this.$router.push("/xxx"),就可以跳到指定路径,从而配合router-view.

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 会消失

2、在el-menu标签中添加router属性

这个方法不一定实用于所有,因为el-menu中有el-menu-item子标签,而这个子标签的index属性就是跳转的路径,这个是特殊的

  1. el-menu标签添加router属性
  2. 添加 router-view
  3. el-menu-item为选项的标签,其index值就是跳转的router

5.6 跳转传值(笔记太垃圾已废弃,具体看5)

1)

<router-link
	:to="{
		path:'/qa/'+ problem.id,
		params:{
			id:problem.id
		}
	}">{{problem.title}}</router-link>
  • path是要传得值,我这里是/qa/id加上id号跳转
  • params是传值,key-value

收:

mounted() {
	this.problem.id = this.$route.params.id
	console.log(this.problem.id)
}

2)router-view传值

在路由弄一个占位符,然后跳到这里时,根据url获得值
在router 的index.js中

{
	  path: '/spit',
	  name: 'SpitIndex',
	  component:SpitIndex
  },{
	  path:'/spit/:id',
	  name:'SpitItem',
	  component:SpitItem
  }
//spit.vue
<router-link :to="'/spit/'+spit._id">{{spit.content}}</router-link>
这里跳转就传如ID了

在跳到到另外一个页面的时候

///spit/:id
console.log(this.$route.params.id)
//打印出跳转的ID

在这里插入图片描述

6、<template slot-scope="scope">

这个东西,很神奇,一般这样用,只能用于template的属性

<el-table
        :data="tableData"
        border
        style="width: 40%">
    <el-table-column
            fixed
            prop="id"
            label="ID"
            width="150">
    </el-table-column>
    <el-table-column
            prop="name"
            label="姓名"
            width="120">
    </el-table-column>
    <el-table-column
            prop="author"
            label="作者"
            width="120">
    </el-table-column>
    <el-table-column
            fixed="right"
            label="操作"
            width="100">
        <template slot-scope="scope">
            <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
            <el-button type="text" size="small">编辑</el-button>
        </template>
    </el-table-column>
</el-table>

<script>
 export default {
    
     methods: {
         test(){
             this.$router.push("/addbook")
         	}
   		}
}
</script>

在这里插入图片描述
点一下查看,就是26.27行的那些代码,定义了一个slot-scope="scope",利用什么滚动的。。我也不懂。然后下一行@click="handleClick(scope.row)",表示点这个查看用到这个方法,并且有个参数,方法中,传的这个scopne.row,可以展示这个框的数据
在这里插入图片描述

7、components

就是复用代码了
使用步骤

  1. 写复用代码vue
  2. 在要用的地方import xxx from "xxxx";
  3. <xxx></xxx>

8、导入css文件

方案1、在main.js中引入方式(全局)

import '@/assets/css/reset.css'

方案2、在.vue文件的

@import "../assets/css/index.css";

9、关掉

根目录的.eslintrc.js

module.exports = {
  root: true,
  env: {
    node: true
  },
  'extends': [
    // 'plugin:vue/essential',
    '@vue/standard'
  ],
  rules: {
    // 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    // 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
  },
  parserOptions: {
    // parser: 'babel-eslint'
  }
}

10、float失败的时候

有时候用了float后,button就不起作用了,style加上这个

style="display: inline-block;"

11、父子组件传值

1)父传子

①通过props的字符串传值

<template>
	//用了子组件,传一个key为id,value则为bookid的值,传给子组件读取
	<UserData :id="bookid"></UserData>
</template>
<script>
	import UserData from '../../components/UserData'

	export default {
		name: "FriendIndex",
		components: {
		//加载儿子
			UserData
		},
		data(){
			return{
				bookid:123
			}
		}
<script>

子:

<template>
	<div>
	//这里读取id,而这个id就是在子组件的props中拿到的
	{{id}}
    </div>
</template>

<script>
	export default {
		name: "",
		//这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里
		props:["id"],
	}
</script>

<style scoped>
</style>
②通过props的对象形式传值

对象的更好,在第一个方法的基础上,添加了限定类型和默认值,其中,类型可以有

  1. String
  2. Number
  3. Boolean
  4. Array
  5. Object
  6. Date
  7. Function
  8. Symbol

<template>
	//用了子组件,传一个key为id,value则为bookid的值,传给子组件读取
	<UserData :bookName="bookName" :price="price" :stroe="stroe" :obj="obj" :doubleType="doubleType"></UserData>
</template>
<script>
	import UserData from '../../components/UserData'

	export default {
		name: "FriendIndex",
		components: {
		//加载儿子
			UserData
		},
		data(){
			return{
				bookName:'金瓶梅',
				price:666stroe:['新华书店','旧华书店'],
				obj:{
					msg:'hello'
				},
				doubleType:'123'
			}
		}
<script>

子:

<template>
	<div>
	//这里读取id,而这个id就是在子组件的props中拿到的
	书名:{{bookName}}   价格:{{price}}
    </div>
</template>

<script>
	export default {
		name: "",
		//props变为对象形式,更方便
		props:{
			//单单限制类型
			bookName:String,
			//限制类型并且提供默认值
			price:{
				type:Number,
				default:0//表示这个key值必须传东西进来
				required:true
			},
			//如果是数组或者对象类型,那么默认值是要写一个函数返回的类型
			stroe:{
				type:Array,
			    default: () => []

			},
			//对象类型
			obj:{
				type:Object,
				default(){
					msg:'hello'
				}
			},
			//即可是数组,也可是数字
			doubleType:[String,Number]
		}
	}
</script>

<style scoped>
</style>
③大坑,子接受不到数据

就直接{{}}可以显示数据,但是在方法或者created中想用就用不了,
在这里插入图片描述
就很诡异,没有值,原因是这父传子需要异步处理,所以有时候会延迟,导致传不了数据到子组件的created和mounted,所以解决办法是在子组件加上个v-if进行判断

//在后面加个判断,这样有才进行传值,就不会异步了
 <LastPhysicalCardSale :date="lastDate" v-if="lastDate"/>

2)子传父

比如发生点触事件,传值给父组件给父组件显示
思路为,子组件写一个@click点击事件,事件里面写this.$emit(事件名,要传的参数),这里就完成了发送事件。
接着就是在父组件里面写一个事件 用于接受参数 的函数,函数的参数就是接受到的数

<template>
	<div>
//3、父组件用到子组件,父传子的话要加一个 @事件 的监听事件,事件名是子组件中$emit定义的,函数名就自己写	
		<TestSon @itemClick="sonClick"></TestSon>
		{{ball}}
	</div>
</template>

<script>
	import TestSon from './testSon.vue'
	
	export default {
		name: "Test",
		data() {
			return {
				ball:''
			}
		},
		methods: {
//4、这里父接受子的事件,函数写一个参数就能接受到了		
			sonClick(item){
				console.log('item',item)
				this.ball=item
			}
		},
		components:{
			TestSon
		}
	}
</script>

<template>
	<div>
//1、点击事件触发函数,传值给父组件,用@click,	
		<button v-for="item in list" @click="btnClick(item)">{{item}}</button>
    </div>
</template>

<script>
	export default {
		name: "TestSon",
		data() {
			return {			
				list:['篮球','足球','羽毛球']
			}
		},	
		methods: {
//2、写函数,里面一定要这样写  	this.$emit('父组件接受的事件',值)	
//注意是父组件接受的事件而不是函数
			btnClick(item){
				this.$emit('itemClick',item)
			}
		},
	}
</script>

点篮球
在这里插入图片描述
点足球
在这里插入图片描述

11.5、父子组件的访问

访问是只能拿到值,读取,并且可以调用方法

1)父访问子

①$children方法访问

<template>
	<div>
		<TestSon ></TestSon>
		<button @click="btnClick">按钮</button>
	</div>

</template>

<script>
	import TestSon from './testSon.vue'
	
	export default {
		name: "Test",
		data() {
			return {
				
			}
		},
		methods: {
//2、父组件访问子组件通过$children访问,得出结果是个数组,可以拿到子组件的很多东西		
			btnClick(){
				console.log('父组件打印子组件',this.$children)
				console.log('父组件打印子组件的变量:'+this.$children[0].message);
				this.$children[0].showMessage()
			}
		},
		components:{
			TestSon
		}
	}
</script>

<style scoped>
  
</style>

<template>
	<div>
		
    </div>
</template>

<script>
//1、子组件这里只提供一个变量和方法,示范是父组件访问子组件的变量和方法
	export default {
		name: "TestSon",
		data() {
			return {
				message:'这是一句话'
			}
		},	
		methods: {
			//这是一个方法
			showMessage(){
				console.log('子组件里面打印:'+this.message)
			}
		},
        created() {
            
        },
		props:{
			
		}
	}
</script>

<style scoped>

</style>

在这里插入图片描述
打印子组件可以有很多东西的
在这里插入图片描述

$children的缺陷

比如父组件写很多个子组件

<TestSon ></TestSon>
<TestSon ></TestSon>
<TestSon ></TestSon>

$children是一个数组,取第二个的值是

this.$children[1]

这样取的,但是如果某一天在第一个后面插入一个子组件,那么数组下标就变了,所以很不人性化,这时候就要使用$refs

②$refs方法访问(推荐)

因为$children的缺陷,$children是数组形式,$refs是使用key的形式,每一个子组件加一个ref标识,在读取的时候根据ref名字读取即可

子和上面的一样

<template>
	<div>
		<TestSon ></TestSon>
//1、给每一个子组件加一个ref的名字
		<TestSon ref="son1"></TestSon>
		<TestSon ref="son2"></TestSon>
		<button @click="allSon">按钮1</button>
		<button @click="oneSon">按钮2</button>
	</div>

</template>

<script>
	import TestSon from './testSon.vue'	
	export default {
		name: "Test",
		data() {
			return {
				
			}
		},
		methods: {
			allSon(){
//2、this.$refs 就是打印全部子组件了			
				console.log(this.$refs); 
			},
			oneSon(){
//3、this.$refs.名字  就是打印某一个子组件的东西了			
				console.log(this.$refs.son1);
				console.log(this.$refs.son1.message);
				this.$refs.son1.showMessage()

			}
		},
		components:{
			TestSon
		}
	}
</script>

<style scoped>
  
</style>

点击按钮1
在这里插入图片描述
点击按钮2
在这里插入图片描述

2)子访问父

其实子访问父的很少的

①$parent

<template>
	<div>
		<TestSon></TestSon>
	</div>

</template>

<script>
	import TestSon from './testSon.vue'
	export default {
		name: "Test",
		data() {
			return {
				message:'我是父组件的一句话'
			}
		},
		components:{
			TestSon
		}
	}
</script>

<template>
	<div>
		<button @click="fu">按钮</button>
    </div>
</template>

<script>
	export default {
		name: "TestSon",
		data() {
			return {
				message:'这是一句话'
			}
		},	
		methods: {
			fu(){
				console.log(this.$parent);
			}
		},
	}
</script>

在这里插入图片描述
这是获取父的

②$root

获取根,最上级的那个

<template>
	<div>
		<button @click="fu">按钮</button>
    </div>
</template>

<script>
	export default {
		name: "TestSon",
		data() {
			return {
				message:'这是一句话'
			}
		},	
		methods: {
			fu(){
				console.log(this.$root);
			}
		},
	}
</script>

12、全局变量localStorage存值、删值、获值

1)存值

	//普通地
 localStorage.setItem("下标",);
 localStorage.setItem("holiday_start_date",that.holiday_time[0]);
 
 //如果值是对象的话,先转换
 localStorage.setItem("下标",JSON.stringify());
 localStorage.setItem("holiday_emp",JSON.stringify(response.data.data[0]));

2)获值

//普通
localStorage.getItem("下标")
localStorage.getItem("is_week")

//对象,
var xx = (JSON.parse(localStorage.getItem("下标")))
var id = (JSON.parse(localStorage.getItem("holiday_emp"))).id;

3)删

localStorage.removeItem("下标")

13、创建对象

setUserInfo(mobile){
	var that = this
	var user = {mobile:mobile}
	}

14、时间格式

数据库是datetime 的2021-03-27 15:25:39,页面显示的是1616858739000

npm install moment --save
main.js中添加

import Moment from 'moment'

// 定义全局时间戳过滤器
Vue.filter('formatDate', function(value) {
  return Moment(value).format('YYYY-MM-DD HH:mm:ss')
})

然后在用的地方

<span class="el-icon-time">注册时间{{user.regdate | formatDate}}</span>

在这里插入图片描述

14.5、过滤器

14的时间格式书写就是用过滤器来写的,一般是这么写的

{{参数| 过滤器名}}

  data: {
	  
  },
  filters:{
  	过滤器名(参数){
  		return 一般是返回什么格式的
  	}
  }

全局配置过滤器

不用每个过滤器都写在一个组件啦,全局配置一个,大家都能用

//main.js
import * as filters from './filters'

Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})
// src/filter/index.js
import Moment from 'moment'
import {trans_tp, payment_type} from '@/views/scenesPay/dict'

/**
 * @param {日期} dateStr
 * @param {格式化模式} pattern
 */
export function dateFormat(dateStr, pattern) {
  if (!dateStr) return ''
  return Moment(dateStr).format(pattern)
}

然后平时用就{{ a | dateFormat }}这样使用

15、分页

<el-pagination
        background
        layout="prev, pager, next"
        :total="hotListTotal"
        page-size="5"
        @current-change="pageHot">
</el-pagination>
  • :total是总数,一般在查询的时候就加上去总数了
  • page-size一页显示多少条数据
  • @current-change="pageHot"点击页数的时候,触发的函数

首页加载时,创建这个函数

getNewProblemList(){
	var that = this
	axios.get('http://192.168.12.128:9012/qa/problem/newlist/1/5').then(function(response) {
		if(response.data.flag==true){
			//数据
			that.$data.problemNewList = response.data.data.rows
			//总有多少条数据
			that.$data.newListTotal = response.data.data.total
		}
		console.log(response);
	})
},

记得在data加上newListTotal 和problemNewList

到这里,获得了多少个函数和初始化了,接下来就是点击页数的时候,触发的函数

//当被点击页数的时候,跳转
pageHot(currPage){
    var that=this;
    axios.get('http://192.168.12.128:9012/qa/problem/hotlist/'+currPage+'/5').then(function (response) {
		if(response.data.flag==true){
			//数据覆盖
			that.$data.problemHotList = response.data.data.rows
		}
		console.log(response);
    })
},
  • currPage是当前点击页数显示的数字

16、axios.delete和平时的不一样

这个B,这个参数和平时的不一样
平时是

var tempData={
	userid:userid
}

axios.post('http://192.168.12.128:9012',tempData).then(function (response) {

	console.log(response);
})

而delete是

var tempData = {
	userid:JSON.parse(localStorage.getItem("userInfo")).id,
	targetuser:targetuser
}
				
axios.delete('http://192.168.12.128:9012/user/user/follow',{data:tempData}).then(function(response) {
	if(response.data.flag==true){
		// that.$message("删除成功")
	}
	that.$message(response.data.message)
	console.log(response);
})

17、路由占位符,组件里面获得数据

就比如

<router-link :to="'/user/'+problem.userid">提出

一个跳转这里使用动态id,比如problem.userid值为5,就会跳转到/user/5,而跳到那个页面,怎么获取这个5呢?

1、路由

先在路由写

  {
	path:'/user/:id'  ,
	name:'UserItem',
	component:UserItem
  }

  • :id是一个占位符

2、组件获取数据

<template>
	<div>
		{{userid}}
    </div>
</template>

<script>
	export default {
		name: "",
		data() {
			return {
				userid:''
			}
		},
		methods: {
			
		},
        created() {
            this.userid = this.$route.params.id
        }
	}
</script>

<style scoped>

</style>

在这里插入图片描述

18、级联选择器

级联选择器
在这里插入图片描述

其数据是这样的

      options: [
        {
          text: '浙江省',
          value: '330000',
          children: [{ text: '杭州市', value: '330100' }
          			{ text: '宁波市', value: '330100' },
          			{ text: '温州市', value: '330100' }],
        },
        {
          text: '江苏省',
          value: '320000',
          children: [{ text: '南京市', value: '320100' }],
        },
      ],

就是children嘛,如果有children(不管是不是空)就继续点下一级,没有就返回数据。但是目前一半返回的数据中,就算最后一级了,也是会有个children:[]的,比如

[
    {
        "id": "441900117000",
        "findname": "凤岗镇",
        "find_quanpin": "fenggangzhen",
        "find_jianpin": "fgz",
        "province": "广东省",
        "displayorder": 441900,
        "netname": "gdwebson.gdnyt.com",
        "netaddress": "1.1.1.1",
        "deptarttype": 1,
        "departtype": 1,
        "tag": "东莞市 , 广东省",
        "children": [
            {
                "id": "901120000000401",
                "findname": "东莞凤岗站",
                "find_quanpin": "dongguanfenggangzhan",
                "find_jianpin": "dgfgz",
                "province": "广东省",
                "displayorder": null,
                "netname": "gdwebson.gdnyt.com",
                "netaddress": "1.1.1.1",
                "deptarttype": 2,
                "departtype": 2,
                "tag": null,
                "children": [],
                "address": "东莞市凤深大道与龙平西路交汇处东北角",
                "stationhotline": "0769-87513786"
            }
        ],
        "address": null,
        "stationhotline": null
    }
]

就算children没有数据,也是有这个字段的。如果只要还有children字段,就会显示下一级,但是下一级是空的没有得选
在这里插入图片描述
这个时候就要去掉最后一级得children字段

// 递归判断列表,把最后的children设为undefined
			getTreeData(data) {
				for (var i = 0; i < data.length; i++) {
					if (data[i].children.length < 1) {
						// children若为空数组,则将children设为undefined
						data[i].children= undefined;
					} else {
						// children若不为空数组,则继续 递归调用 本方法
						this.getTreeData(data[i].children);
					}
				}
				return data;
			}

19、:class绑定的几种方式

在这里插入图片描述
或者一个标签几个动态的class,可以这样写
在这里插入图片描述

20、计算属性

简单形式

之前没遇到过的,比如有firstName和lastName两个属性,在页面上我们要

{{firstName}} + {{lastName}}

这样显示,就很麻烦

有个计算属性的东西,可以自动拼接字符的

{{fullName}}

<script>
	xxxx省略代码
	data:{
		firstName:'jack',
		lastName:'white'
	},
	computed:{
		fullName:function(){
			return this.firstName + ' ' + lastName
		}
	}
</script>

data里面没有fullName,但是在computed里面显示了,页面显示jack white
值得一提的是,data的值改变,其computed也是会重新计算一次的

get形式

其实我们这是缩写,其实本来是这样的

{{fullName}}

<script>
	xxxx省略代码
	data:{
		firstName:'jack',
		lastName:'white'
	},
	computed:{
	//这里如果直接fullName :function(){},就是只取get方法
		fullName:{
			get:function(){
				return this.firstName + ' ' + lastName
			}
	}
</script>

其实也有set的

老面向对象了,也是有set的。比如你什么button按钮想改变值,也是可以的

{{fullName}}

<script>
	xxxx省略代码
	data:{
		firstName:'jack',
		lastName:'white'
	},
	computed:{
	//这里如果直接fullName :function(){},就是只取get方法
		fullName:{
			get:function(){
				return this.firstName + ' ' + lastName
			},
			set:function(newValue){
			//这里把值给保存给data了
				const names = newValue.spit(' ');
				this.firstName = names[0];
				this.lastName = names[1];
			}
	}
</script>

21{{}}里面直接写函数也是可以的

{{getFullName()}}

<script>
	xxxx省略代码
	data:{
		firstName:'jack',
		lastName:'white'
	},
	methods:{
		getFullName(){
			return this.firstName + ' ' + lastName
		}
	}
</script>

22、各个修饰符

在这里插入图片描述
@keyup.enter就是触发回车的事件之类的

.stop修饰符

一个div有个点击事件,div里面有个button有个点击事件,那么点button的时候,会触发div点击事件和button点击事件。
那么我想点button只触发button而不触发div事件,可以@click.stop="xx"
在这里插入图片描述

23、.native

自定义组件的时候,直接@click="xx"无反应,在自定义组件的时候应该加上@click.native="xx"

24、遍历对象

<ul v-for="(value,key,index) in person">{{value}}--{{key}}--{{index}}</ul>

//js
  data() {
	  return {
		  person:{
			  name:'小强',
			  age:22
		  }
	  }
  },

小强–name–0
22–age–1

25、函数的不定长参数

function sum(...num){
	//code
}

sum(10,20,30,35)

26、vue中数组的一些自带方法

push

数组末插入数据

this.arr.push('aa')

pop

删除最尾的数据

this.arr.pop()

shift

删除数组最前面的一个元素

this.arr.shift()

unshift

再数组最前面添加一个元素

this.arr.unshift('aa')

splice

其有好几个作用

删除元素
this.arr.splice(从第几个开始删,删除几个元素)
//从第二个元素开始删除,删除2个   [a,b,c,d] --> [a,b]
this.arr.splice(2,2)
替换元素
this.arr.splice(从第几个开始替换,替换几个,替换的元素)
//从第二个元素开始替换,删除2个   [a,b,c,d] --> [a,b,e,f]
this.arr.splice(2,2,'e','f')
插入元素
this.arr.splice(第几个后面插入,0,插入的元素)
//从第二个元素后面插入   [a,b,c,d] --> [a,b,e,f,c,d]
this.arr.splice(2,0,'e','f')

27、js高阶函数

比如const nums = [10,20,111,112]

filter

filter中的参数是回调函数,其回调函数必须返回一个boolean值。返回值是数组。filter的回调函数会循环一遍数组的

用来过滤的,比如取出数组小于100的数字,普通的

let newNums = []
for(let n in nums){
	if(n<100){
		newNums.push(n)
	}
}

但是可以这样简写

//用newNums来接住数组,然后filter里面写回调函数,return true 或者 false
let newNums = nums.filter(function(n){
	return n < 100
})

map

和filter差不多,只不过filter规定返回布尔值,map的返回值不规定
比如要求每个数*2

let newNums = []
for(let n in nums){
	newNums.push(n*2)
}

高阶

let newNums = nums.map(function(n){
	return n*2
})

reduce

对数组进行汇总,他是这样的

数组.reduce(回调函数(上一次遍历的值,当前遍历的值){
//	code
},初始值)

比如将所有数加起来

const nums = [10,20,111,112]
let total = 0
for(let n in nums){
	total + =n
}

可以这样写

let total = newNums.reduce(function(preValue,n){
	return preValue + n
},0)

第一次遍历,preValue = 0,n=10 , return 10
第二次遍历,preValue = 10,n=20 , return 30
第三次遍历,preValue = 30,n=111 , return 143
第三次遍历,preValue = 143,n=112 , return 255

28、checkbox多选框的使用

在这里插入图片描述
比如这个,选中哪个,就记录哪个。
之前我是每一个都弄一个点击事件,然后再push和pop操作的。
后来发现视频,不用的,直接,每一个input都是v-model绑定一个数组,然后直接在下面{{数组}}就可

	  <input type="checkbox" value="篮球" v-model="hobbies">篮球
	  <input type="checkbox" value="唱歌" v-model="hobbies">唱歌
	  <input type="checkbox" value="跳舞" v-model="hobbies">跳舞
	  <input type="checkbox" value="足球" v-model="hobbies">足球

	<h2>爱好:{{hobbies}}</h2>
//------
  data() {
	  return {
		  hobbies:[]
	  }
  },

在这里插入图片描述

29、v-model修饰符

lazy

懒加载,由于v-model双向绑定,比如input还在输入的时候,data会时时改变

<input type="text" v-model.lazy="msg">
		{{msg}}
		//------
		
		data() {
			return {
				msg:''
			}
		},

但我们想在input中输完时,按下回车或者焦点离开输入框,data值才改变
在这里插入图片描述
还没按回车,后面的值不会改变
在这里插入图片描述
按下回车,值改变

number

就是说input的时候,只能输入数字类型,如果是<input type="number">data里面判断类型时string而不是number,这时候这样用就可以

		<input type="number" v-model.number="msg">
		{{typeof msg}}
		//------
		
		data() {
			return {
				msg:''
			}
		},

在这里插入图片描述

30、父传子,避免用v-model直接绑定props中的值

比如

<template>
	//用了子组件,传一个key为id,value则为bookid的值,传给子组件读取
	<UserData :id="bookid"></UserData>
</template>
<script>
	import UserData from '../../components/UserData'

	export default {
		name: "FriendIndex",
		components: {
		//加载儿子
			UserData
		},
		data(){
			return{
				bookid:123
			}
		}
<script>

子:

<template>
	<div>
	{{id}}
	//这里用了父子
	<input type="text" v-model="id">
    </div>
</template>

<script>
	export default {
		name: "",
		//这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里
		props:["id"],
	}
</script>

<style scoped>
</style>

v-model绑定了props而不是data,会有错误
在这里插入图片描述
官方建议data先拿到props,然后再对data进行双向绑定
修改后子:

<template>
	<div>
	{{reallyId}}
	//这里用了父子
	<input type="text" v-model="reallyId">
    </div>
</template>

<script>
	export default {
		name: "",
		//这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里
		props:["id"],
		data(){
			return {
				reallyId:this.id
			}
		}
	}
</script>

<style scoped>
</style>

31、watch监听某一值的改变

和data同级,某一值发生改变时,执行的代码

<template>
	<div>
		<input type="text" v-model="reallyId">
    </div>
</template>

<script>
	export default {
		name: "",
		data(){
			return {
				reallyId:'123'
			}
		},
		watch:{
			//一个新值,一个旧值
			reallyId(newValue,oldValue){
				//要执行的代码
			}
		}
	}
</script>

<style scoped>
</style>

32、插槽slot

插槽嘛,插入啥变变成啥
应用场景多为一个重复的组件,但是组件和组件之间又有些不一样的需求。有点类似于Java的集成,把大家共性的东西都打包,要怎么改怎么用,就是子类的事了。

在这里插入图片描述
导航条,左边有些事返回,有些是菜单,但是总的来说,大家都是左中右3个地方,我们就可以将这些共性打包

1)简单插槽

<!-- 子 -->
<template>
	<div>
		<!-- 这里都显示 -->
		我是子组件
<!--1、 solt是插槽,要什么的就在这里插入 -->
		<slot></slot>
		<br><br>
    </div>
</template>
<!-- 父 -->
<template>
	<div>
<!-- 2、在子组件里面插入你想要插入的东西,这个东西就会在solt中替换的 -->	
		<TestSon><button>按钮</button></TestSon>
<!-- 3、没有插入的就啥事没有发生 -->		
		<TestSon></TestSon>
<!-- 4、或者你插入其他的 -->		
		<TestSon><i>我是i</i></TestSon>
<!-- 5、插入多个的话,会都加载,将多个都在solt中替换 -->		
		<TestSon>
			<button>我是button</button>
			<h2>我是h2</h2>
		</TestSon>
	</div>

</template>

在这里插入图片描述

3)具有默认值的插槽

如果调用10次插槽,8次要求是button,2次要求是h2,那么每一个我都要些button和h2,但是button是8次啊,明显又麻烦了,所以有默认值,和Java抽象方法的默认值这种差不多

<!-- 父 -->
<template>
	<div>
		<!-- 2、覆写默认值 -->
		<TestSon><p>老子不想要按钮</p></TestSon>
		<!-- 3、空白就直接用默认值 -->
		<TestSon></TestSon>
		<TestSon><button>老子是自己写的按钮</button></TestSon>

	</div>

</template>
<!-- 子 -->
<template>
	<div>
		我是子组件
		<!-- 1、定义了一个solt,但有默认值 -->
		<slot><button>按钮</button></slot>

		<br><br>
    </div>
</template>

3)具名插槽

上面是子组件里面只有一个solt,但是如果想几个solt怎么办?

<!-- 子 -->
<template>
	<div>
	<!-- 写3个插槽 -->
		<slot>左边</slot> 
		<slot>中间</slot>
		<slot>右边</slot>

		<br><br>
    </div>
</template>
<!-- 父 -->
<template>
	<div>
		<TestSon></TestSon>
		<!-- button覆盖3个插槽 -->
		<TestSon><button>按钮</button></TestSon>

	</div>

</template>

在这里插入图片描述
如果我们只想替换中间那个,可以这样写

<!-- 子 -->
<template>
	<div>
		<!-- 1、给每一个插槽起名字-->
		<slot name="left">左边</slot> 
		<slot name="center">中间</slot>
		<slot name="right">右边</slot>

		<br><br>
    </div>
</template>
<!-- 父 -->
<template>
	<div>
		<TestSon></TestSon>
		<TestSon>
			<!-- 在子组件里面,插入template ,属性v-solt:插槽名 ,然后再在button里面插入想要的东西-->
			<template v-slot:center>
				<button>按钮</button>
			</template>
		</TestSon>

	</div>

</template>

v-slot 只能添加在 <template>
在这里插入图片描述

4)作用域插槽

子组件的插槽的slot中的样式是子组件写的,但是,如果我想用到子组件插槽中的数据,但是只是想改变样式而已。

就是说,比如子组件默认插槽值是
在这里插入图片描述
但是我想换成这样子
在这里插入图片描述
其中,这些值是子组件的值,这时候如果要改变样式并且拿到子组件的值,要这样做

<!---->
<template>
	<div>
//2、把值给父组件读取,需要加上 :自定义名字="变量"  ,这样父组件通过名字就能读取了
		<slot :language="language">
//1、这里是slot中的默认样式		
			<ul>
				<li v-for="item in language"> {{item}} </li>
			</ul>
		</slot>
		<br><br>
    </div>
</template>

<script>
	export default {
		name: "TestSon",
		data() {
			return {
				language:['java','php','js']	
			}
		},	
</script>
<!---->
<template>
	<div>
		<TestSon></TestSon>
		<TestSon>
//3、v-slot:default="slotProps" ,这里的 slotProps就可以拿到子组件插槽中的所有变量(名字也是自己起的)
			<template v-slot:default="slotProps">
			//4、这里读slotProps,会拿到全部值
				<div>slotProps: <h2>{{slotProps}}</h2>
				</div>
				<br>
			//5、slotProps.什么  ,就是子组件插槽中定义的值
				<div>slotProps.language: <h2>{{slotProps.language}}</h2>
				</div>
				<br>
			//6、遍历
				<span v-for="item in slotProps.language">{{item}}-</span>
			</template>
		</TestSon>

	</div>

</template>

在这里插入图片描述

另一个例子

33、js的模块化导出导入

js是弱语言,没有Java这么强的封装性和继承性。
如果正常导入js文件,是<script src="xx.js"></script>,那么如果导入的几个js文件有重名变量,函数,会覆盖。
那么模块化就是把每个模块之间隔绝,重名变量就不会覆盖。
导出就是模块隔绝后,开个接口给别人用,就是导出export
导入就是导入别的模块来使用,导入import

简单的模块化

js就写一些普通的函数,或者变量,别人用就要这样用

<script src="main.js" type="module"></script>

简单的导入导出

//a.js,定义一个变量和函数
// 1、写东西
var flag = true

function sum(num1, num2) {
    return num1 + num2

}
//2、导出
export {
    flag,sum
}
//b.js导入a.js,并调用东西
//3、导入js
import {flag,sum} from './a.js'

//4、引用变量和函数
if(flag){
	console.log(sum(10,20))
}

导出方式

1)写完再导出
var flag = true

function sum(num1, num2) {
    return num1 + num2
}

//2、导出
export {
    flag,sum
}
2)边写边导出
export  var flag = true

export  function sum(num1, num2) {
    return num1 + num2
}
3)导出函数
export class Person(){
	run(){
		console.log('跑')
	}
}
4)export default

上面的导入,都是import {xx} from 'x.js',但是平时vue的都是import 自己起名字 from 'a'
那么这个自己起名字就是通过export的

//a.js
var num =666
export default num
import shuzi from './a.js'
console.log(shuzi)

666

export default一个文件只能存在一个

导入方式

1)一个个导入
//a.js,定义一个变量和函数
var flag = true
var num = 123

function sum(num1, num2) {
    return num1 + num2

}
//2、导出
export {
    flag,sum,num
}
//b.js导入a.js,并调用东西
import {flag,sum,num} from './a.js'

//4、引用变量和函数
if(flag){
	console.log(sum(10,20))
}
2)一起导入
//b.js导入a.js,并调用东西
import * as obj from './a.js'

//4、引用变量和函数
if(obj.flag){
	console.log(obj.sum(10,20))
}

34、webpack打包JS

webpack xxx.js xx.js

35、简单理解npm

npm是一个maven管理器,控制一堆包的,但是npm不像maven那么高级,所有包都放在一个仓库,他
是每一个项目都有自己的仓库,叫node_modules。

npm install xx -g保存到全局,但有些东西是每个项目都要单独安装的,仅适用于类似webpack这种全局的打包的

36、脚手架创建文件没有webpack.config.js

https://blog.csdn.net/zz00008888/article/details/109536466

vue cli2.x才会有webpack.config.js,3.x之后就类似spring boot的自动配置一样,要加的话往里面加个vue.config.js进行修改即可

37、npm install错误

目前只知道几种解决方案

1)npm clean cache --force

注意在cmd用管理员身份打开
其其实就是把C:\Users\master\AppData\Roaming\npm-cache删除,清下缓存

38、咋看vue版本

网上说的 vue -V看的是cli版本的!!!
在这里插入图片描述
首先vue版本准确说是怎么看项目的vue版本,打开项目的node_modules\vue\package.json,查看版本
在这里插入图片描述
可以看到我用的是vue2.x而不是3.x
emmmm
我一直以为自己用3.x了。。。。。

39、箭头函数

其实就是Java8的lambda

const obj = {
  sum(num1,num2){
    return num1+num2
  }
}

const test = function (str){
  console.log(str);
}

test(666)
obj.sum(10,20)

简写

const sum = (num1,num2) =>{
  return num1+num2
}

sum(10,20)

如果函数里面,只有一个参数可以

then((data) => {
	console.log(data);

then(data => {
	console.log(data);

40、url的hash和history

hash方式

比如在https://www.jd.com/
输入location.hash='/foo',就到了https://www.jd.com/#/foo
但是页面没有刷新,而且也有个后退按钮
在这里插入图片描述
当输入history.back()时,又退回到了https://www.jd.com/
其实这玩意就是个栈,请求一层层往上加,back就去掉一层

history方式

history.pushState({},'','home')
在这里插入图片描述

history.go()

history.back() == history.go(-1)
history.go(-2)就回退2个

如果是history.go(1)就返回刚才的页面,其实就是这个
在这里插入图片描述

41、深入浅出路由

之前都是回用就好了,现在回顾一下
router\index.js

import Vue from 'vue'
//1、先导入插件
import VueRouter from 'vue-router'
import Index from '../views/Index.vue'

//2、插件的使用方式,再使用Vue.use(xxx)
Vue.use(VueRouter)

//4、routes定义在router里面的数组
const routes = [
  {
    path: '/',
    name: 'Index',
    component: Index
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

//3、定义一个变量,3个选项嘛,最后一个变量是数组
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

//5、最后面要导出啦
export default router

再到根目录的main.js

import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
//导入那个 ./router/index.js
import router from './router'
import store from './store'
import './plugins/element.js'

Vue.config.productionTip = false

//这里就是new Vue了,有个router,就是简写的  router:router
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

42、路由懒加载

其实就是

{
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }

或者是

const About = () => import(/* webpackChunkName: "about" */ '../views/About.vue')
{
    path: '/about',
    name: 'About',
    component: About 
  }

好处是,这样打包后,加载速度会更块,以后都推荐这种方式

43、导航守卫

就是一个router里面的东西,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航,有点拦截器的感觉,可以配合安全验证之类的进行拦截跳转。

官网介绍:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB

比如我们想根据url显示不同的title(就是浏览器标签页中图标右边的文字)
在这里插入图片描述

1)在router/main.js添加meta

{
	  path:'/test',
	  name:'Test',
	  component:Test,
	  meta:{
		  title:'测试1'
	  }
  },{
	  path:'/test2',
	  name:'Test2',
	  component:Test2,
	  meta:{
		title:'测试2'
	}
  }

meta是数据的描述注释之类的,除了title还有其他很多的。

2)router/main.js 里面添加全局前置守卫

//beforeEach是前置守卫,在跳转前执行的函数,其有3个变量,from跳转到to,然后next是个函数,可以中断,可以继续跳转
router.beforeEach((to, from, next) => {
	//设置标题
	window.document.title = to.meta.title
	//可以看看有啥
	console.log(to);
	//next一定要有,无的话会报错
	next()
})

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打印to可以看到有很多信息,之后我们甚至可以判断路径url显示自定义的东西之类的,
如果有时候判断不了,例如子子组件,可以用matched来解决子的路径

3)next

  • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

  • next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

  • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

就是说,我们可以判断有没有登陆之类的,没有登陆就next(‘/login’)这种

4)后置守卫

router.afterEach((to, from) => {
  // ...
})

就是后置啦,没有next

5)路由独享的守卫

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

6)组件内的导航守卫

//和data,created同级
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }

44、keep-alive的使用

为社么要用keep-alive

因为一个页面,有created和destory两个函数嘛,组件创建和毁灭,当从A到B时,A毁灭B创建。但我后退一步,又要B毁灭再A创建。这样很麻烦,虚拟dom弄了好多次,而且如果A到B再到A,那么A原本的东西就会都不见了,因为A已经被毁灭过了,保存的临时数据页销毁了。keep-alive就是解决这个问题得到。

案例

这个案例原本可以简单点的,但是这个问题公司也会用到,一起讲了

比如我们页面是这样
在这里插入图片描述
跳转到到home时,识别或者重定向跳转到/home/toutiao

home有两个子:头条和新闻,和home同级的有my

当点击home时,或者点击头条时,跳转到home/toutiao
在这里插入图片描述

点击新闻时跳转到home/news
在这里插入图片描述
点击my时跳转到/my
在这里插入图片描述
当点击home的新闻,再点击my,再点击到home的时候,如果是使用重定向,会跳转到home/toutiao,那么我刚才浏览的明明是新闻,还要继续点一个新闻才到新闻。我想在home/news时,点my,再点home,会跳到home/news而不是home/toutiao
在这里插入图片描述 点my=》在这里插入图片描述 点home=》 在这里插入图片描述
可以这样做
首先路由

	{
		path: '/home',
		name: 'home',
		component: home,
		redirect :'/home/toutiao',
		children: [{
			path: 'news',
			name: 'news',
			component: news,
		}, {
			path: 'toutiao',
			name: 'toutiao',
			component: toutiao,
		}]
	}, {
		path: '/my',
		name: 'my',
		component: my
	},
//app.vue
<template>
	<div>
	//根目录就2个按钮
		<button @click="tohome">home</button>
		<button @click="tomy">my</button>
		//1、加了keep-alive就行
		<keep-alive>
			<router-view></router-view>
		</keep-alive>
	</div>
</template>

<script>
	export default {
		methods: {
			tohome() {
				this.$router.push('/home')
			},
			tomy() {
				this.$router.push('/my')
			}
		}
	}
</script>
//home.js
<template>
	<div>
		我是home <br>
		//到了home里面,有2个按钮,根据按钮在router-view显示对应
		<el-button @click="totoutiao"> 头条</el-button>
		<el-button @click="tonews"> 新闻</el-button>
		<keep-alive>
			<router-view></router-view>
		</keep-alive>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				//1、先定义path,这样就类似重定向
				path: '/home/toutiao'
			}
		},
		methods: {
			totoutiao() {
				this.$router.push('/home/toutiao')
			},
			tonews() {
				this.$router.push('/home/news')
			}
		},
		//2、在keep-alive里面才有这个函数,表示当这个页面活跃的时候,
		//从home/new跳转到my的时候,home不会被销毁,而且记得了上一次呆的地方是news,所以再点击home时,执行activated跳到home/news
		activated() {
			this.$router.push(this.path)
		},
		//组件内后置守卫,跳转了之后的
		beforeRouteLeave(to, from, next) {
			console.log(this.$route.path)
			//要离开了,记得这次是从哪里离开的,方便再次加入
			this.path = this.$route.path
			next()
		}
	}
</script>

其实说那么多就是为了表达keep-alive是可以方式组件再次被创建和销毁的,这个案例我觉得工作会用到所以记下的

注意点

我们先看下生命周期
created和mounted,然后接下来就是平常的东西,如果或数据发生变化,发生updated,然后销毁destoryed。
keep-alive有2个函数,activated和deactivated ,一个是某个组件活跃的时候(用到的时候),另一个就是组件不活跃(没用到的时候)

不让某个节点有keep-alive

比如详情页之类得,点击详情页再返回,再点击其他的详情页,因为用了keep-alive,不会再执行mouth和created,所以这个时候需要排除某些组件

<keep-alive exclude="xxx组件名">

</keep-alive>

45、为啥url有时候有#

这是因为VueRouter设置的模式是hash模式,设置成history就不是#了

const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes
})

判断什么url干什么事

比如,tabbar的,根据url为/index的时候,首页按钮显示红色,其他都是黑色
在这里插入图片描述
就是设置2个,活跃的时候,显示红色,不活跃显示黑色,这个活跃值就这样判断

	if(this.$route.path.indexOf('/home') !==-1){
		//code...
	}

str.indexOf('key'):判断str中是否包含key,没有则返回-1,有则返回第几个开头的字

小实例?

		created() {
			console.log(this.$route);
			if(this.$route.path.indexOf('/home/toutiao') !==-1){
				console.log('trueeeeee!')
			}
		},

在这里插入图片描述

46、配置路径别名

如果导入一些图片之类的,如果文件移动了,什么…/,…/…/之类的很多,取个别名就好多了
默认@就是src,比如src/main.js,就是@/main.js

其他更多的可以自定义设置名字

//vue.config.js
const path = require('path');        //引入path模块
function resolve(dir){
    return path.join(__dirname,dir)  //path.join(__dirname)设置绝对路径
}
module.exports={
    chainWebpack:(config)=>{
        config.resolve.alias
            //set第一个参数:设置的别名,第二个参数:设置的路径
            .set('@',resolve('./src'))
            .set('assets',resolve('.src/assets'))
            .set('components',resolve('./src/components'))
            .set('views',resolve('src/views'))
    }
}


其他用view,就

//import就这样写
import xx from 'views/xxx'
//如果非import,前面要加~
<img src="~xxx" alt="">

47、Promise

这是一个异步编程的一种解决方案
其实我之前敲代码也有过,比如我axios时,发送一个请求,当拿到结果后,再从拿到的结果再次发送一个请求。或许没啥事,但是当时写得是挺乱得,如果以后还有套娃嵌套娃嵌套娃,那就很恶心了,而promise就是为了让代码更好看,而且执行效率高,结构分明的东西。

Promise主要是用于有异步处理的地方

其大概结构是这样写的

	new Promise((resolve, reject) => {
		//...code
		//成功时执行resolve函数,实际上就是执行then的函数
		resolve('success');
		//失败时执行reject函数,实际上就是执行catch的函数
		reject('err')
	}).then((data) => {
		//成功之后的事
		console.log(data);
	}).catch((err) => {
		//失败之后的事
		console.log(err);
	})
  • Promise的参数为一个函数,那个函数又有2变量resolve和reject,但resolve和reject也都是函数(不用写具体内容)。于是就可以用箭头函数简写啦
  • 其在里面进行操作异步处理,在执行成功的地方写入resolve函数传参。就会自动跳到then执行代码。在执行失败的地方写入resolve函数传参,就会自动跳到catch执行代码
    或者是
	new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('resolve')
			reject('reject')
		}, 1000);
	}).then(data=>{
		//执行成功的代码
		console.log(data);
	},err=>{
		//执行错误的代码
		console.log(err);
	})
	
	//其其实就是then(function(data),function(err))
	//第一个执行成功的代码,第二个执行失败的代码

小案例

比如我们这有个套娃的,用setTimeout模仿异步请求啦
一个setTimeout里面,执行代码,然后执行完里面又有个setTimeout,执行代码,里面又有setTimeout

	setTimeout(() => {
		console.log('11111');

		setTimeout(() => {
			console.log('222222');

			setTimeout(() => {
				console.log('333333');
			}, 1000);
		}, 1000);
	}, 1000);

在这里插入图片描述
打印是可以打印,就是有点恶心。用Promise优雅一下

	new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('1111')
			reject('err')
		}, 1000);
		//执行第一层成功代码
	}).then((data) => {
		console.log(data);
		//code..

		return new Promise((resolve, reject) => {
			setTimeout(() => {
				resolve('2222')
				reject('err')
			}, 1000);
			//执行第二次成功代码
		}).then((data) => {
			console.log(data);
			//code...

			return new Promise((resolve, reject) => {
				setTimeout(() => {
					resolve('3333')
					reject('err')
				}, 1000);
				//执行第3次成功代码
			}).then((data) => {
				console.log(data);
				//执行第3次失败代码
			}).catch((data) => {
				console.log(err);
			})

			//执行第二次失败代码
		}).catch((data) => {
			console.log(data);
		})
		//处理第一层的错误代码
	}).catch((data) => {
		console.log(data);
	})

虽然看起来还是恶心,但是,如果代码逻辑很复杂,这个就好

链式调用

还有链式调用,还有链式调用的简写方式,但我实在学不懂了,简写以后再学吧

all方法

我觉得比较罕见,就是2个异步任务,要任务A成功,任务B成功,2个一起成功了才执行自定义代码

	//all里面是个数组,每一个元素都是new一个Promise对象
	Promise.all([
		new Promise((resolve, reject) => {
			//code
		}),
		new Promise((resolve, reject) => {
			//code
		})
		//几个异步任务完成后,都是成功执行后,再来到then函数
		//其中,result是一个数组,result[0]是第一个异步任务完成的回调数据,result[1]是第二个异步任务完成的回调数据,
	]).then(result => {
		console.log(result);
	})

比如

			Promise.all([
				new Promise((resolve, reject) => {
					setTimeout(() => {
						resolve({
							name: '小强',
							age: 18
						})
					}, 1000);
				}),
				new Promise((resolve, reject) => {
					setTimeout(() => {
						resolve({
							name: '小明',
							age: 22
						})
					}, 1000);
				})
			]).then(result => {
				console.log(result);
				
			})

结果为:

[
    {
        "name": "小强",
        "age": 18
    },
    {
        "name": "小明",
        "age": 22
    }
]

48、导入插件 或者 创建自己的工具类和插件

就是用别人的插件之类的
目前我只会怎么用别人的插件,创建自己的插件(工具类)我还不会

使用别人的插件

用官方的vuex为例子,其他第三方插件我不知道
主要是我查不到正确的做法是什么,官方这样导入的,其他应该或许大概也是这样做的?

  1. 先下载插件(npm install xxx)
  2. 新创个文件,专门做这个插件的事情
    //  store/index.js
    
    //1、导入vue和vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    //2、使用插件  Vue.use(插件)
    Vue.use(Vuex)
    
    //3、导出插件,export default 插件对象
    //可以是new xx直接写
    //也可以是const x = new 插件对象,写好再export default x
    export default new Vuex.Store({
      state: {
      },
      mutations: {
      },
      actions: {
      },
      modules: {
      }
    })
    
  3. 再在main.js中使用插件
    import Vue from 'vue'
    //4、导入插件
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
    //5、在这里写,这是官方的,我不知道第三方插件在new Vue里面,还是Vue.use
      store,
      render: h => h(App)
    }).$mount('#app')
    
    
    然后其他的也能通过$store使用

49、vuex

1)简单使用

就是之前遇到的,2个毫无相关的组件,要用同一个变量。之前是通过全局变量localStorage来实现的,但这个不是响应式的,不好做,查了下发现原来vuex就是做全局变量的,而且是响应式的。

vuex在store/index.js下
要的全局变量就在state里面加,比如

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  	//设置全局变量
    count:1000
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

别人用的话

我是全局变量counter:{{this.$store.state.count}}

就可

我是全局变量counter:1000

2)修改vuex中的数据

既然知道vuex是进行全局变量的,那么肯定能读能写,读就直接this.$store.state.变量名去读,但是写的话不可以通过传统的this.$store.state.变量名 ++,因为不单单你一个组件在写,其他组件也可能会写,这样直接改会发生异步错误处理。vuex都帮我们做好了

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:1000
  },
  mutations: {
    //1、vuex定义一个方法,为count++,参数加state
    increment(state){
      state.count++
    },
    //vuex定义一个方法,为count--
    decrement(state){
      state.count--
    },
    //还可以传参,第一个是state,第二个就是传参数据,如果是多个传参数据,可以用对象传,再 对象.xx
    incrementNum(state, num) {
      state.count += num
    }
    
  },
  actions: {
  },
  modules: {
  }
})

<template>
	<div>
		我是全局变量counter:{{this.$store.state.count}}
		<!-- 2、普通的点击事件 -->
		<button @click="add">+</button>
		<button @click="jian">-</button>
		<button @click="addNum(5)">+5</button>
		<button @click="addNum(10)">+10</button>
	</div>
</template>

<script>
	export default {
		name: "",
		methods: {
			add(){
			//3、事件里面 this.$store.commit('vuex中方法名')  来进行值得修改
				this.$store.commit('increment')
			},
			jian(){
				this.$store.commit('decrement')
			},
			addNum(num){
				this.$store.commit('incrementNum', num)
			},
		},
	}
</script>

这样子就可以改,而且可以在插件里面看到值得修改过程
在这里插入图片描述
在这里插入图片描述

3)getters

这类似于普通组件的computed,什么计算属性,可以写一些tostring的东西

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 1000,
    array: [10, 20, 30, 40]
  },
  mutations: {
  },
  getters: {
    //重构,显示对应的东西
    toStringCount(state) {
      return 'count:' + state.count
    },
    //可以配合过滤
    more20(state) {
      return state.array.filter(n => {
        return n > 20
      })
    },
    //参数可以加getters,调用getters的方法
    more20Lent(state, getters) {
      return getters.more20.length
    },
    //甚至可以自定义传参
    moreNum(state) {
      //return 回调函数,参数num就是要大于的数
      return num => {
        //然后过滤
        return state.array.filter(n => {
          //得到的数过滤回来
          return n > num
        })
      }
    }
  },
  actions: {},
  modules: {}
})
		<!-- 直接显示 -->
		<h2>{{this.$store.getters.toStringCount}}</h2>
		<h2>{{this.$store.getters.more20}} </h2>
		<h2>{{this.$store.getters.more20Lent}} </h2>
		<h2>{{this.$store.getters.moreNum(10)}} </h2>

在这里插入图片描述

3.5)getters还有更方便的读写方式

const getters = {
  sid: state => state.user.sid
}
export default getters
const store = new Vuex.Store({
  getters
})

然后在用的地方

import {mapGetters} from "vuex";

  computed: {
    ...mapGetters(['sid']),
      //其是会自动转换成
      // sid(){
   	 //   return this.$store.state.sid
 	   // }
  },

然后就能简单地使用啦

console.log(this.sid)

4)特殊的mutations提交风格

上面的是普通的,下面这个特殊的

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 1000,
  },
  mutations: {
  	//这种接受的是一个对象
    incrementNum(state, payload) {
      console.log(payload);
      state.count += payload.num
    }
  },
})
	<button @click="addNum(5)">+5</button>
	<button @click="addNum(10)">+10</button>
	
	<script>
	//方法
	addNum(num){
		//type和一个传值
		this.$store.commit({
			type :'incrementNum',
			num
		})
	},	
	
	</script>

按下+10

{
    "type": "incrementNum",
    "num": 10
}

5)Mutation响应规则

2中是介绍了vuex中修改数据,但那仅限于修改,增加和删除我们都没讲
比如我们要修改和删除,先看错误的.

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    obj: {
      name: '小强',
      age: '23'
    }
  },
  mutations: {
    updateObj(state) {
    	//obj增加一个key
       state.obj['address'] = '深圳'
       //obj删除一个key
       delete state.obj.age
    }
  },
})
		<h2>{{this.$store.state.obj}}</h2>
		<button @click="changeObj">修改对象</button>


			changeObj(){
				this.$store.commit('updateObj')
			}

在这里插入图片描述
点击修改对象按钮,也没效果

在这里插入图片描述
在这里插入图片描述
这么看来是已经修改了,但可惜的是,这2者不支持响应式布局(下面会讲哪些不是响应式的)

应该这么改

    updateObj(state) {
      // state.obj['address'] = '深圳'
      // delete state.obj.age
      //用这2个进行添加和修改
      Vue.set(state.obj,'address','深圳')
      Vue.delete(state.obj,'age')
    }

6)Mutation常量类型

就是,我们commit传的是字符串嘛,为了统一性,用常量来定义这个字符串,然后传入这个常量即可

//mutations_types.js
export const INCREMENT = 'increment'
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
//导入
import * as type from './mutations_types.js'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 1000,
    array: [10, 20, 30, 40],
    obj: {
      name: '小强',
      age: '23'
    }
  },
  mutations: {
    //vuex定义一个方法,为count++
    // increment(state) {
    //   state.count++
    // },
    //将名字和替换成常量
	[type.INCREMENT](state) {
      state.count++
    },
  },

})
	<button @click="add">+</button>
	

	import * as type from '../store/mutations_types.js'

	add() {
		// this.$store.commit('increment')
		this.$store.commit(type.INCREMENT)
	},

7)Action

上面的操作都是在mutation中进行的同步操作,但是很多情况是要异步操作的,而mutation不支持异步操作的,需要配合action使用。所以需要异步操作就方法->action->mutation,不需要异步就方法->mutation

  mutations: {
  	//在action中异步处理完后,在mutations中修改全局变量
      muAsync(state,payload){
      state.count +=payload.count
    }
  },
  actions: {
  	//2、在action中,定义异步操作,在异步操作成功时context.commit到mutatuions
    acAsync(context,payload){
      setTimeout(() => {
        context.commit('muAsync',payload)
      }, 1000);
    }
  },
		<h2>------------------</h2>
		<button @click="async(2)">异步操作+2按钮</button>
		{{this.$store.state.count}}
//js
		//1、在方法里面进行异步修改全局变量,dispatch跳转到action,第二个参数是对象
		async(num){
			this.$store.dispatch('acAsync',{count:num})
		}
ps

如果actions是在某个模块里面的,比如是

export default {
	actions:{
	  setUserId ({ commit }, userId) {
   	  commit('SET_USER_ID', userId)
  },		
	}
}
//store.index.js
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'

Vue.use(Vuex)

//  文件加载
const modulesFiles = require.context('./modules', true, /\.js$/)

//  遍历文件导出store对象
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})
const store = new Vuex.Store({
  modules,
  getters
})

export default store

在这里插入图片描述
其他地方可直接用store.dispatch('user/setUserId', userId)

①结合Promise进行回调处理

就是在方法中,this.$store.dispatch('acAsync',{count:num})成功完成后,进行的一些操作

  actions: {
  
    acAsync(context, payload) {
      //返回一个promise,这样子,方法就可以继续写then了
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          //commit到mutations
          context.commit('muAsync', payload)
          //成功
          resolve('success')
        }, 1000);
      })
    }
    
  },
	methods: {
		async (num) {
			this.$store.dispatch('acAsync', {
				count: num
				//写回调
			}).then(res => {
				console.log(res);
			})
		}
	}

8)Module模块化

因为什么都往里面塞的话,这个index.js就会很大不方便,有个模块化

const Person ={
  state:{},
  mutations:{},
  getters:{},
  actions:{}
}

export default new Vuex.Store({
  state: {
    count: 1000,
    array: [10, 20, 30, 40],
    obj: {
      name: '小强',
      age: '23'
    }
  },
  mutations: {},
  getters: {},
  actions: {},
  modules: {
    //其实就是Person:Person的简写
    Person  
  }
})
①使用
import Vue from 'vue'
import Vuex from 'vuex'
import * as type from './mutations_types.js'

Vue.use(Vuex)

const Person ={
  state:{
    name:'詹姆斯'
  },
  mutations:{
    //注意这里的名字不要和根或其他任何模块重名
    updateName(state,payload){
      //state是本模块的state
      state.name = payload.name
    }
  },
  getters:{
    //普通的getters
    fullname1(state){
      return state.name + '1'
    },
    //调用本模块的getters
    fullname2(state,getters){
      return getters.fullname1 + '2'
    },
    //还可以用根的state数据
    fullname3(state,getters,rootState){
      return getters.fullname2 + rootState.count
    }
  },
  actions:{
    //异步操作也是一样
    syncUpdateName(context,payload){
      console.log(context,payload);
      setTimeout(() => {
        context.commit('updateName',payload)
      }, 1000);
    }
  }
}

export default new Vuex.Store({
  state: {
    count: 1000,
    array: [10, 20, 30, 40],
    obj: {
      name: '小强',
      age: '23'
    }
  },
  mutations: {},
  getters: {},
  actions: {},
  modules: {
    //其实就是Person:Person的简写
    Person  
  }
})

在这里插入图片描述
点击异步改变名字后

在这里插入图片描述
在这里插入图片描述

9)vuex项目结构

我们希望进行模块化的目录结构
在这里插入图片描述
store下,index是总,然后actions、mutations就管理总的action之类的,然后一个modules文件夹,管理各个模块,一个模块就有自己的action、mutations之类的

10)总结

vuex是个很好的全局变量管家,就是用起来有点麻烦。
要先预设什么全局变量,就在state中设置,
同步请求就在mutation中写好,方法再调用mutations
异步请求就方法调用action在action中进行异步处理,得到结果后再给mutations进行全局变量的修改
所有的全局变量修改一定要通过mutations进行修改。绕过mutations修改数据官方不建议,会造成数据错误

50、axios

1)crud

then和catch是每个都会有的
axios.request(config),其他的比如get:axios.request(url[,config])

①get

两者用的时候,都是在方法里面用的,格式为

	axios.get('路径').then(res => {
          console.log(res );
      }).catch(err =>{
      	console.log(err);
      })
      
②post
	axios.post('路径',json类型的数据).then(res => {
          console.log(res );
      })

或者

	axios.post('路径',{params:json类型对象}).then(res => {
          console.log(res );
      })
③put
	axios.put('路径',json类型的数据).then(res => {
          console.log(res );
      })
④delete
	axios.delete('路径',{data:json类型数据}).then(res => {
          console.log(res );
      })

2)all并发请求

	//返回的是一个数组
	axios.all([axios.get('url1'), axios.get('url2')])
		.then(res => {
			console.log(res);
	})
	//或者一个个地返回,推荐这种
	axios.all([axios.get('url1'), axios.get('url2')])
		.then(axios.spread((res1, res2) => {
			console.log(res1);
			console.log(res2);
	}))	
	

3)axios的配置信息

一般弄完基本的东西,有特殊的可以在里面加一些配置

①直接在某一个axios请求里面加进去
	axios.all([
			axios({
				//config
				baseURL: 'http://192.168.12.128:9012',
				url: 'user/user/follow'
			}),
			axios({
				//config
				baseURL: 'http://192.168.12.128:9012',
				url: 'user/user/follow',
				params: {
					type: 'all'
				}
			}),
		])
		.then(axios.spread((res1, res2) => {
			console.log(res1);
			console.log(res2);
		}))
②全局的配置
	//公共baseURL抽出来
	axios.default.baseURL = 'http://192.168.12.128:9012'

	axios.all([
			axios({
				url: 'user/user/follow'
			}),
			axios({
				url: 'user/user/follow',
				params: {
					type: 'all'
				}
			}),
		])
		.then(axios.spread((res1, res2) => {
			console.log(res1);
			console.log(res2);
		}))
③配置表

https://github.com/axios/axios

{
   // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // default

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data, headers) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },

   // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },

  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,

   // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // default

  // `adapter` 允许自定义处理请求,以使测试更轻松
  // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },

 // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
  // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

   // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // default

  // `responseEncoding` indicates encoding to use for decoding responses
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // default

   // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

   // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

   // `maxContentLength` 定义允许的响应内容的最大尺寸
  maxContentLength: 2000,

  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // default

  // `socketPath` defines a UNIX Socket to be used in node.js.
  // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
  // Only either `socketPath` or `proxy` can be specified.
  // If both are specified, `socketPath` is used.
  socketPath: null, // default

  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定义代理服务器的主机名称和端口
  // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
}

4)实例封装

如果一个文件写默认配置baseURL =xxx,那么会影响全部,但往往很多时候需要从不同的数据库拿不同的数据,那baseURL就不一定了
一种是,利用nginx反向代理,或者是spring cloudbus的那个,将所有请求统一起来再分发下去
另一种就是自己封装一层axiox实例,我们一般是用这个方法的

	//request.js
	//传入config,config会自动覆盖的
	export function request(config){
		//有个axios.create专门用于创建实例
		const instance = axios.create({
			baseURL:'http://192.168.12.128:9012',
			timeout:5000
		})

		//返回的是一个promise
		return instance(config)
	}

用的话

	import request from 'request.js'
		//传入的是config,上面那个表,
	request({
		url: '/user/user/follow'
	}).then(res => {
		console.log(res);
	}).catch(err => {
		console.log(err);
	})

5)拦截器

分为请求拦截器和响应拦截器,写再axios得到实例封装里面的,就是返回 return instance(config)之前

	//请求拦截器
	//use后第一个参数函数是成功的函数
	instance.interceptors.request.use(config => {
		//请求可以在这里设置一个转圈圈的东西,等在相应后,将转圈圈样式改变就可

		//可以检查config里面有没有token令牌之类的

		//或者检查config里面有没有不对的信息
		// 都通过后再放行,如果不通过就跳转到其他页面
		return config
		//失败的函数
	}, err => {
		//code
	})
	//响应拦截器
	instance.interceptors.response.use(res => {
		//code
		return res
	}, err => {
		//code
		return err
	})
	

51 、css常量

	//:root是定义常量的
	:root{
		--color-text: #666;	
	}

	//这就是使用
	.xxx{
		color: var(--color-text);
	}

52、tabbar的编写(怎么让一个东西固定)

(0)怎么固定

先说一下怎么让一个div在页面上固定,给css

//比如固定住上面的导航条
.x{
	position: fixed;
    top: 0;
    left: 0;
    right: 0;
}

//比如在一个中心固定住
  .leftSideBackground {
    position: fixed;
    bottom: 37px;
    left: 20px;
    //这样就固定了距离左下多少
    width: 7px;
    height: 40px;
    }

(1)tabbar

只是提供一个思路,用插槽完成

因为下面的tabbat不知道会有几个,所以可以先定义一个tabbar,然后一个插槽完成,插槽里面再细分到每个item,然后用总的 MainTabBar完成。
在这里插入图片描述

<!-- tabbar -->
<template>
  <div id="tab-bar">
    <slot></slot>
  </div>
</template>

<script>
	export default {
		name: "TabBar"
	}
</script>

<style scoped>
  #tab-bar {
    /* 本身的样式 */
    background-color: #f6f6f6;
    height: 49px;
    border-top: 1px solid #eee;
    box-shadow: 0px -1px 1px rgba(150,150,150,.08);

    /* 定位相关 */
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;

    /* 利用flex进行布局 */
    display: flex;
    text-align: center;
  }
</style>
<!-- tabbarItem,每一个插槽都要有活跃图片,未选择图片,文字 -->
<template>
  <div id="tab-bar-item" @click="itemClick">
  	//记得要再slot外再用一层div包住,因为div才能用样式之类的
    <div class="item-icon" v-show="!isActive"><slot name="icon"></slot></div>
    <div class="item-active-icon" v-show="isActive"><slot name="active-icon"></slot></div>
    <div class="item-text" :style="activeStyle"><slot name="text"></slot></div>
  </div>
</template>

<script>
	export default {
		name: "TabBarItem",
    props: {
			link: {
				type: String,
        required: true
      }
    },
    computed: {
			isActive() {
				return this.$route.path.indexOf(this.link) !== -1
      },
      activeStyle() {
				return this.isActive ? {'color': 'red'} : {}
      }
    },
    methods: {
			itemClick() {
				this.$router.replace(this.link)
      }
    }
	}
</script>

<style scoped>
  #tab-bar-item {
	/* 这个很重要 */
    flex: 1;
  }

  .item-icon img, .item-active-icon img {
    width: 24px;
    height: 24px;
    margin-top: 5px;
    vertical-align: middle;
  }

  .item-text {
    font-size: 12px;
    margin-top: 3px;
    color: #333;
  }
</style>
MainTabBar,往tabbar中插入一些tabbaritem
<template>
  <tab-bar>
    <tab-bar-item link="/home">
      <img slot="icon" src="~assets/img/tabbar/home.svg" alt="">
      <img slot="active-icon" src="~assets/img/tabbar/home_active.svg" alt="">
      <div slot="text">首页</div>
    </tab-bar-item>
    <tab-bar-item link="/category">
      <img slot="icon" src="~assets/img/tabbar/category.svg" alt="">
      <img slot="active-icon" src="~assets/img/tabbar/category_active.svg" alt="">
      <div slot="text">分类</div>
    </tab-bar-item>
    <tab-bar-item link="/cart">
      <img slot="icon" src="~assets/img/tabbar/cart.svg" alt="">
      <img slot="active-icon" src="~assets/img/tabbar/cart_active.svg" alt="">
      <div slot="text">购物车</div>
    </tab-bar-item>
    <tab-bar-item link="/profile">
      <img slot="icon" src="~assets/img/tabbar/profile.svg" alt="">
      <img slot="active-icon" src="~assets/img/tabbar/profile_active.svg" alt="">
      <div slot="text">我的</div>
    </tab-bar-item>
  </tab-bar>
</template>

  <script>
    import TabBar from 'common/tabbar/TabBar'
    import TabBarItem from 'common/tabbar/TabBarItem'

    export default {
      name: "MainTabBar",
      components: {
        TabBar, TabBarItem
      }
    }
  </script>

<style scoped>

</style>


52.5、flex: 1;

css中的一个属性,用于水平布局

53、前端mvc

这个问题也是困扰了我很久,就是我的请求都直接写在每个组件方法里面,这样不好

其实可以参考spring mvc,每个组件的方法请求相当于controller,然后弄个中间层,将逻辑代码放到servlet层,因为只有读取到的数据后操作不一样,读取数据的操作都是一样的。可能A组件要根据ID找数据,B组件也是根据ID找数据,那么就可以让根据ID找数据丢在一个文件里面就行

	//封装好一个request.js
	//传入config,config会自动覆盖的
	export function request(config){
		//有个axios.create专门用于创建实例
		const instance = axios.create({
			baseURL:'http://192.168.12.128:9012',
			timeout:5000
		})
		
		//拦截器
		
		//返回的是一个promise
		return instance(config)
	}
//home.js,专门处理home的东西
import requestfrom './request'


export function getHomeMultidata() {
  return axios({
    url: '/home/multidata'
  })
}
//	别的地方要用的话
  import {getHomeMultidata} from "network/home";
		
		//返回的就是一个promis,可以then和catch
        getHomeMultidata().then(res => {
          //xxx
          
        })

53、process.env.NODE_ENV

可以获得当前是什么环境,怎么拿到我就不知道了。。就只会用

54、手机浏览器看控制台

一个插件,叫vconsole

55、前端处理跨域+转发跳转

事情的原因是,发送一个http://localhost:8080/applySiCard/applyInfo/v1/realNameInfo的请求,等半天没反应,就觉得很奇怪,大佬说这里发送的是localhost,但实际上vue进行了设置

//vue.config.js
module.exports = {
  devServer: { // 包含关系
    proxy: {
      '/applySiCard': {
        target: 'http://10.11x.x.x:8099',
        // target: 'http://192.168.xxx:8099',
        changeOrigin: true //跨域
      }
    }
  }
},

这个做了转发也做了跨域问题,只要是localhost:8080/applySiCard/xxx的,都会跳转到10.11x.x.x:8099/applySiCard/xxx,F12也看不到的
这里是做了一个转发的,这样就不用在每个请求都加ip和端口了

值得一提的是,这些操作devServer.proxy都是用于开发环境的,开发环境才会有跨域问题,为了解决跨域才会有这个操作。因为本地是127.0.0.1,会有跨域。
如果是线上,前端和后端在同一个主机上,地址当然耶一样,不用再改了。

56、setInterval和clearInterval

settimeout是多少秒仅执行一次后消失了嘛,这玩意是隔多少秒就执行一次
clearInterval是用来取消的
比如发验证码,60s内不允许重复发

    startBusRefresh() {
      if (this.busRefreshTimer) return
      this.time = 60
      this.busRefreshTimer = setInterval(() => {
        this.time--
        if (this.time == 0) {
          this.stopBusRefresh()
        }
      }, 1 * 1000)
    },
    stopBusRefresh() {
      this.busRefreshTimer && clearInterval(this.busRefreshTimer)
      this.busRefreshTimer = null
    },

57、vue中,方法异步用async关键字

async examin() {
//xxx
}

58、this.$forceUpdate()强制刷新

原理是调用强制更新方法this.$forceUpdate()会更新视图和数据,触发updated生命周期
能少用就少用吧,刷新一下对用户体验不友好

59、!important 解决兼容性

.el-table__expanded-cell:hover {
  background-color: #f7f7f7 !important;
}

60、/deep/、::v-deep、>>>

这3都是表示一个东西,修改原生样式
这得从一件诡异的事情说清
公司做一个弹窗嘛
在这里插入图片描述
二话不说上vant的官网复制粘贴去
然而复制粘贴后,却啥都没有
在这里插入图片描述

①为什么会这样

?!为啥这样,对比了一下官方的css,发现样式被覆盖了
在这里插入图片描述
这背景都被搞了,是被自己写的全局css覆盖了。。。
在这里插入图片描述
所以我们现在在vue文件里面改局部css样式就好(不要搞全局css)

这是官网的:
在这里插入图片描述
尽管有点不一样,但不要怕,把背景搞成白色就算赢
不知道为啥上面是有#app .van-action-sheet,而官方是.van-action-sheet,可能是全局变量设置了什么东西吧。。。
然后就改

②错误1

  .van-action-sheet{
    background: white;
  }

在这里插入图片描述
真是非常神奇呢,然后看了网上说是改原生样式,会在后面加一串东西
在这里插入图片描述

③错误2

  /deep/ .van-action-sheet{
    background: white;
  }

在这里插入图片描述
嗯?不会。。

④正确

简单且朴素

#app{
  .van-action-sheet{
    background: white;
  }
}

在这里插入图片描述
我也不知道为什么后面有那串东西还能成功
在这里插入图片描述

61、根据什么环境读取不同的参数数据

.env 全局默认配置文件,不论什么环境都会加载合并
.env.development 开发环境下的配置文件
.env.production 生产环境下的配置文件

PS:属性名必须以VUE_APP_开头,比如VUE_APP_XXX

# .env.development
VUE_APP_MOCK_LOCAL = true

用的话:

const isMockLocal = process.env.VUE_APP_MOCK_LOCAL;

62、win和linux的node环境不一样

忘记哪个依赖了,install后会报错说没有安装python,然后安装个python就行(有些Linux自带py环境)。然后还有一个是淘宝镜像的问题,在后面加--registry=https://registry.npm.taobao.org

63、路由请求时转圈圈

在这里插入图片描述
这种,可以在一个请求方法里面写,也可以搞一个通用post里面写,我这在一个请求方法里面写的

export function queryARES(param, showLoading = true) {
  let loading = null
  //等待状态
  if (showLoading) {
    loading = Toast.loading({
      duration: 40 * 1000, // 持续展示 toast
      forbidClick: true,
      message: '正在处理,请稍等'
    })
  }
  return new Promise((resolve) => {
    return post({
      param: param,
      url: '/openapi/v1/mohrss/call_api',
    }).then((res) => {
      //清除等待状态
      loading?.clear()
      resolve(res);
    }).catch((error) => {
      //清除等待状态
      loading?.clear()
      console.log(error);
      resolve(false);
    });
  });
}

64、async的作用

我以前一直以为async是为了解决异步问题,现在发现是配合promise使用的
如果一个请求返回promise,没有async为

  created() {
    const res =  xxx(param, true)
    console.log(res)

  },

在这里插入图片描述
如果有async

  async created() {

    const res = await xxx(param, true)

在这里插入图片描述

65、富文本编辑器

npm install @packy-tang/vue-tinymce
把https://gitee.com/panjiachen/vue-element-admin/tree/master/src/components中的Tinymce复制下来到一样的地方(对,npm安装后还不能直接用。。而且这个是已经编写好的了,很方便)
然后用就简单了

<template>
  <div class="components-container">
    <aside>
      这是富文本编辑器,用v-model绑定html形式的值
    </aside>
    <div>
      <tinymce v-model="content" :height="300" />
    </div>

    <aside>
      这是富文本编辑器的结果,用v-html绑定html形式的值。保存到数据库直接用html形式保存即可
    </aside>
    <div class="editor-content" v-html="content" />
  </div>
</template>

<script>
import Tinymce from '@/components/Tinymce'

export default {
  name: 'TinymceDemo',
  components: { Tinymce },
  data() {
    return {
      content:
      `<h1 style="text-align: center;">Welcome to the TinyMCE demo!</h1><p style="text-align: center; font-size: 15px;"><ul>
        <li>Our <a href="//www.tinymce.com/docs/">documentation</a> is a great resource for learning how to configure TinyMCE.</li><li>Have a specific question? Visit the <a href="https://community.tinymce.com/forum/">Community Forum</a>.</li><li>We also offer enterprise grade support as part of <a href="https://tinymce.com/pricing">TinyMCE premium subscriptions</a>.</li>
      </ul>`
    }
  }
}
</script>

<style scoped>
.editor-content{
  margin-top: 20px;
}
</style>

66、图片加载不了

普通的<img src='https://dgapa.dongguantong.com.cn/dgtmgm/upload/image/20210801115039.jpg' alt="" style="height: 50px;width: 50px">就加载不出来呢

然后百度说加这个就好了 <meta name="referrer" content="no-referrer" />

67、非父子组件传值

vuex

第一个方法就是vuex了,在前面已经介绍

新建一个Vue对象busEvent

新建一个Vue对象作为中间值

// 创建busEvent.js   作用:非父子组件间传值
import Vue from 'vue'
const busEvent = new Vue()
busEvent.dicts = []
export default busEvent

然后用的话

import busEvent from '@/utils/busEvent'

//xxxx函数里面,读取缓存
      if (busEvent.dicts[dict_type]) {
        this.dicts[dict_type] = busEvent.dicts[dict_type]
        return busEvent.dicts[dict_type]
      }
//写缓存
      busEvent.dicts[dict_type] = res.data
      return busEvent.dicts[dict_type]

68、注册全局的$xxx

之前不是会有$router表示路由嘛,我们也想要$xx自己的也可以的

//main.js
import Vue from 'vue'
import * as echarts from 'echarts';

Vue.prototype.$echarts = echarts

69、父组件用子组件的方法

      <template slot="content">
<!--        要加个ref就对了-->
        <userinfo-Mgt-Table ref="userinfoMgtTable" />
      </template>

<script>
import userinfoMgtTable from "@/components/Table/personas/userinfoMgtTable";

export default {
  components: {
    userinfoMgtTable,
  },
}  
</script>

然后子组件userinfoMgtTable里面有个方法searchByParam

//userinfoMgtTable
    searchByParam(param) {
      this.pageNum = 1;
      this.searchParam = Object.assign({}, param);
      this.reqBillingRecordList();
    },

父组件要用的话

	this.$refs.子组件名.方法
	
    this.$refs.userinfoMgtTable.searchByParam(param);

70、Object.assign(a,b)

这可是个好东西,让b的属性加到a里面,

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

Object { a: 1, b: 4, c: 5 }

71、Object.keys(object).forEach(e => {您的代码}) 用于查看对象的key

类似于for…i…
下面两段代码的结果都一样

// 创建对象
var person = {
    name: 'hjm',
    age: 18,
    school:"SKD University",
    home: 'China'
}
 
// 用forEach()进行遍历
var keys = Object.keys(person).forEach(function (e) {
    console.log("person ", e, ": ", person[e]);
});
// 创建一个对象
var person = {
    name: 'hjm',
    age: 18,
    school:"SKD University",
    home: 'China'
}
 
// 获得对象属性名组成的数组
var keys = Object.keys(person);
 
// 用于存储匹配的属性值
var value = [];
 
// 用for进行遍历
for (var i = 0,len = keys.length; i < len; i++) {
    var key = keys[i];
    value[i] = person[key];
    console.log("person ", key, ": ", value[i]);
}

在这里插入图片描述

用于将对象下标对应的值为空

      searchForm = {
        user_id: "asd",
        age_tag: "qwe",
        sex_tag: "r",
        card_type_tag: "w",
        active_tag: "q",
        parking_tag: "s",
      },
      
      //将对象值为空
      Object.keys(this.searchForm).forEach(key => {
        this.searchForm[key] = ''
        console.log(this.searchForm)
      })
     

sex_tag
age_tag
card_type_tag
active_tag
parking_tag
ex_tag

72、开发依赖和生产依赖

就开发的时候嘛,有些是要用的,但是正式上线就不用了,就npm install xxx --save-dev
普通的就npm install xxx --save

73、mock的简单使用

以前的mock我都是参照vue element admin他里面做好的来做的,但是我直接复制过去发现不行,就参考了这个文章是可以的
PS:最好的办法还是vue element admin里面的mock方法,但是我不会抽出来,只能用比较差一点的方法

npm install mockjs --save-dev

1、在src同级目录添加mock-server文件夹内涵3个文件如下

index.js //假接口入口配置文件
 
similar.js //小模块,不让一整个模块都写在index里面
 

2、vue.config.js内配置

devServer:{
	proxy: config.dev.proxyTable,//参照位置
	...
	before: require('./mock-server/index'), //添加

}

3、index.js

//导入拆分的模块
const similar = require('./similar')

module.exports = function (app) {

	//然而我写得还是不好,还是要一个个地导入
  similar.querySimilarUserPersonaListByPage(app);
  similar.querySimilarUserPersonaNum(app)

}

similar.js

const Mock = require('mockjs');
const Host = process.env.VUE_APP_HOST + '/persona/label/v1'

//生成mock地随机数
const json = Mock.mock({
  result_code: '@integer(1, 3)',
  message: "success",
  data: {
    id: '@increment',
    title: '@title(5, 10)',
  }
})

module.exports = {

	//里面就写各个的方法
  querySimilarUserPersonaListByPage(app) {
    app.post(Host + '/querySimilarUserPersonaListByPage', function (rep, res) {
      res.json(Mock.mock(json));
    });
  },

  querySimilarUserPersonaNum(app) {
    app.post(Host + '/querySimilarUserPersonaNum', function (rep, res) {
      res.json(Mock.mock(json));
    });
  }

}

73.5、由于mockjs很久没人理了,所以推荐使用Better-Mock

Better-Mock基于mockjs,所以可以兼容使用
Better-Mock文档
mock文档
主要是Better-Mock可以直接拦截
在这里插入图片描述

74、数据字典的几种使用方法

过滤器

//main.js
import * as filters from './filters'

Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})
// src/filter/index.js
// 导入的2个就是json
import {trans_tp, payment_type} from '@/views/scenesPay/dict'

export function formatScenesDict(value) {
  let flag = false

  for (let transTpElement of trans_tp) {
    if (value === transTpElement.code) {
      flag = true
      return transTpElement.name
    }
  }

  for (let paymentTypeElement of payment_type) {
    if (value === paymentTypeElement.code) {
      flag = true
      return paymentTypeElement.name
    }
  }

  if (flag == false) return value

}

// src/views/scenesPay/dict
export const payment_type = [
  {code: '0101', name: "中银通支付"},
  {code: '0102', name: "微众虚拟卡支付"},
  {code: '0103', name: "东莞银行虚拟卡支付"},
  {code: '0104', name: "广发银行虚拟卡支付"},
  {code: '0105', name: "农商银行虚拟卡支付"},
  {code: '0201', name: "联盟银行信用卡支付"},
  {code: '0202', name: "非联盟信用卡支付"},
  {code: '0203', name: "联盟银行储蓄卡支付"},
  {code: '0204', name: "非联盟银行储蓄卡支付"},
  {code: '0205', name: "社保卡支付"},
  {code: '0206', name: "储蓄卡快捷支付"},
  {code: '0207', name: "信用卡快捷支付"},
  {code: '0301', name: "微信支付"},
  {code: '0302', name: "支付宝支付"},
  {code: '0303', name: "云闪付支付"},

]

75、判断当前是什么环境

环境只有3个,开发、测试、生产,其中,开发和测试是可以直接判断的
process.env.NODE_ENV 为development时,开发环境
为production时,是生产环境

判断是否为测试环境

这个大有研究,从原理说起

//package.json
{
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test-build": "vue-cli-service build --mode testpdct",
    "lint": "vue-cli-service lint"
  },
}

一般比如看这里嘛,第一个是开发,第二个是生产
第三个是我们自定义的,自定义为测试,后面的–mode testpdct就是让我们用了.env.testpdct这个文件

一般来说,配置什么全局变量的都是这样的
在这里插入图片描述
开发和生产是用vue cli创建就有的,testpdct是人工创建的,名字就是package.json里面的--mode xxxx
然后在.env.testpdct里面定义一个VUE_APP_ENV = test,用的时候process.env.VUE_APP_ENV === 'test'就能判断是不是测试环境了

76、更新依赖

直接npm update xxxx

77、组件传值不单单是传值

比如这个
在这里插入图片描述

	<van-empty
	  :image="image"
	  v-if="bus_tickets&&bus_tickets.length == 0">
	  <template slot="description">
	    <span>您还没有行程 赶紧下单吧! <br> <div class="clickTips" @click="refresh">点我刷新试试</div></span>
	  </template>
	</van-empty>
<style>
  .van-empty {
    padding: 0;

    /deep/ .van-empty__image {
      width: 135px;
      height: 85px;
      margin-top: 57px;
      margin-bottom: 15px;
    }

    /deep/.van-empty__description {
      margin-top: 0;
      .clickTips {
        text-align: center;
        color: rgb(94, 201, 255);
      }
    }
  }
</style>

在这里插入图片描述
就,原本description只传个文字,但是用<template slot="description">后,里面可以添加样式啥的,,而且那cssvan-empty__description还能直接用??

78、传图片路径失败时还可以用require来做

      <van-empty :image="image">
      </van-empty>
      
<script>
  data () {
    return {
      image: require('@/assets/images/empty.png')
    }
  },
</script>

79、$on和$emit进行非父子组件通讯

非父子组件通讯

//busEvent.js
// 创建busEvent.js   作用:非父子组件间传值
import Vue from 'vue'
const busEvent = new Vue()
export default busEvent

//一般来说这么用的
//用之前记得import busEvent
var bus = new Vue()

// 在组件 B 绑定自定义事件
bus.$on('id-selected', function (id) {
  // ...
})
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)

80、阻止冒泡事件

在这里插入图片描述
每个按钮都有@click事件,然后按钮里面有个X也有@click事件,但是按了X,连外面button得事件也触发了,为了解决,这就是阻止冒泡事件(大学干小南教过)
vue解决就是在X得事件加stop@click.stop="xxx"
https://cn.vuejs.org/v2/api/#v-on

81、保存登录状态

一般来说,登录后,保存到localStorage和vuex,这样,不刷新不退出的情况下就能一只知道登录状态和用户了
但是一般都会刷新的,那么就用到全局路由前置守卫

router.beforeEach((to, from, next) => {
}

在每次要跳转之前,判断localStorage的用户信息是否存在,如果不存在,就没登录。如果存在,就把localStorage中的用户信息同步到vuex进行相应化数据,其他用就getter用就好了
比如

router.beforeEach((to, from, next) => {
  const uniUserInfo = uni.getStorageSync('userInfo')
  const uniToken = uni.getStorageSync('token')

  if (uniToken){
    if (uniUserInfo){
      store.dispatch('user/setToken', uniToken)
      store.dispatch('user/setUserInfo', uniUserInfo)
    }else{
      setTokenAndUserInfo(uniToken)
    }
  }
  // console.log(uniToken)
  // console.log(uniUserInfo)
  next();
});

82、el-select中的el-option中value为对象时

比如这个

   <el-form-item label="上一级字典" prop="sup_dict">
     <el-select v-model="sup_dict" placeholder="请选择" >
       <el-option v-for="item in dictInfo" :label="item.dict_name" :value="item" :key="item.id"></el-option>
     </el-select>
   </el-form-item>
//dictInfo为
dictInfo:[
    {
        "id": "d3f34d529e26494eb974772ccc8d4612",
        "dict_no": "1",
        "dict_name": "阵地打卡活动",
        "dict_type": "activity_type",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "10",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:11:08",
        "update_time": null,
        "is_delete": "0"
    },
    {
        "id": "e152ef7a0f374a8389b2d5219f6921fd",
        "dict_no": "2",
        "dict_name": "主题积分活动",
        "dict_type": "activity_type",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "100",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:11:49",
        "update_time": null,
        "is_delete": "0"
    },
    {
        "id": "181c11e860fa44e79b1c12dedf6c31ae",
        "dict_no": "1",
        "dict_name": "实体卡刷卡",
        "dict_type": "sign_type",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "呵呵",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-10 15:28:46",
        "update_time": "2021-11-11 09:03:43",
        "is_delete": "0"
    },
    {
        "id": "78fef122fdbb416a99f3d951b3254cfa",
        "dict_no": "2",
        "dict_name": "手动补卡",
        "dict_type": "sign_type",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "无",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:09:15",
        "update_time": null,
        "is_delete": "0"
    },
    {
        "id": "909176513a6240cd889c13008e803ed7",
        "dict_no": "3",
        "dict_name": "人脸打卡",
        "dict_type": "sign_type",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "无",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:09:45",
        "update_time": null,
        "is_delete": "0"
    },
    {
        "id": "f3e65a8b463d4f69b51700eb0c0f77b9",
        "dict_no": "1",
        "dict_name": "正常",
        "dict_type": "status",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "无",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:13:00",
        "update_time": null,
        "is_delete": "0"
    },
    {
        "id": "85471e06f1024bfe9dbca5c4622f6b55",
        "dict_no": "2",
        "dict_name": "失效(置黑)",
        "dict_type": "status",
        "dict_desc": null,
        "sup_dict_no": null,
        "sup_dict_type": null,
        "field1": "无",
        "field2": null,
        "field3": null,
        "status": "1",
        "create_time": "2021-11-11 10:13:24",
        "update_time": null,
        "is_delete": "0"
    }
]

就很简单的,选项为for循环,显示为dict_name,点中后值为整个item对象,通过v-model绑定到sup_dict中,但是,事实是这样
在这里插入图片描述
为什么都乱了。。。
查文档
在这里插入图片描述
就是说要在el-select加多个value-key=“id”,其中id为唯一

     <el-form-item label="上一级字典" prop="sup_dict">
       <el-select v-model="sup_dict" placeholder="请选择" value-key="id">
         <el-option v-for="item in dictInfo" :label="item.dict_name" :value="item" :key="item.id"></el-option>
       </el-select>
     </el-form-item>

就好了
在这里插入图片描述

83、连接日期和时间,返回Date

const date = '2018-12-24';
const time = '23:59:59';

const dateTime = moment(`${date} ${time}`, 'YYYY-MM-DD HH:mm:ss').format();

84、解决异步的邪门歪道,诡异的办法

有些东西就尼玛离谱,逻辑上一点毛病都没有,但他妈的vue或者是js就是存在着这些异步同步的问题。
比如

console.log(this.form)
this.form =  obj2DateRange(this.form)
console.log(this.form)

明明经过函数的变化都已经发生改变了,但2次输出都是变化后的效果,但老子要的是一个变化前和一个变化后的效果啊

再比如提交表单的

const reqParam = this.form
//然后将reqParam提交上去,进行更新

但这个,修改里面变的情况下,外面你的table也会变,但这还没提交呢在这里插入图片描述
遇事不决,遇到这种人眼逻辑看起来没毛病的,我们可以统一用一种诡异的方法解决

      this.form.id = row.id
      this.form.act_no = row.act_no
      this.form.act_name = row.act_name
      this.form.act_type_no = row.act_type_no
      this.form.site_no = row.site_no
      this.form.act_desc = row.act_desc
      this.form.status = row.status
      this.form.act_duration = row.act_duration
      this.form.score_once = row.score_once
      this.form.dateRange = row.dateRange
      this.form.start_date = row.start_date
      this.form.start_time = row.start_time
      this.form.end_date = row.end_date
      this.form.end_time = row.end_time
		//this.form = row //感觉和这一样,但效果确实不一样

或者

              const {
                id,
                act_no,
                act_name,
                act_type_no,
                site_no,
                act_desc,
                status,
                act_duration,
                score_once,
                dateRange, //在做了在做了
                start_date,
                start_time,
                end_date,
                end_time
              } = this.form

              const reqParam = {
                id,
                act_no,
                act_name,
                act_type_no,
                site_no,
                act_desc,
                status,
                act_duration,
                score_once,
                dateRange, //在做了在做了
                start_date,
                start_time,
                end_date,
                end_time
              }
              //const treqParam = this.form //看起来和这一样,但实际上就尼玛不一样

看起来就是搁这搁这得感觉,但实际上他就是能解决一些异步得奇怪行为,就尼玛 诡异离谱

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值