1. array 数组方法
var str1 = [12,2,"hello"];
var str2 = ["world"];
console.log(str1.valueOf()==str1);
console.log(str1)
- concat() 合并数组,并返回合并之后的数据
console.log(str1.concat()) //[12, 2, "hello", "world"]
- join() 使用分隔符,将数组转为字符串并返回
console.log(str1.join("-")); //[12-2-hello]
- unshift() 在第一位新增一或多个数据
console.log(str1.unshift("23")) //4
console.log(str1))//['23', 12, 2, 'hello']
- push() 在最后一位新增一或多个数据
console.log(str1.push("23"))//4
console.log(str1)//[12, 2, 'hello', '23']
- shift() 删除第一位,并返回删除的数据
console.log(str1.shift());//12
console.log(str1)//[2, 'hello']
- pop() 删除最后一位,并返回删除的数据
console.log(str1.pop()); //hello
console.log(str1)//[12, 2]
- reverse() 反转数组,返回结果
console.log(str1.reverse());//['hello', 2, 12]
- slice(startIndex, endIndex) 截取指定位置的数组,并返回,不会改变原数组,不包含
endIndex
console.log(str1.slice(0,2));//[12, 2]
- splice(start,num,data1,data2,...) 向数组中指定位置添加,删除,替换数组中的元素,然后返回被删除/替换的元素
添加
console.log(str1.splice(0,0,32));//[] 首位,添加32
console.log(str1)// [32, 12, 2, 'hello']
删除
console.log(str1.splice(0,1));首位, 删除第一个//[12]
console.log(str1)// [2, 'hello']
替换
console.log(str1.splice(0,1,44));首位, 替换第一个//[12]
console.log(str1)// [44, 2, 'hello']
- sort() 对数组内的数据进行排序
var str1 = [12,2,1,"hello"];
var str1 = [12,2,1,"hello"];//[1, 12, 2, 'hello']
console.log(str1.sort());
- toString() 转换成字符串,并返回,类似于没有加任何参数的join()
console.log(str1.toString());//12,2,hello
- valueOf() 返回数组对象的原始值
console.log(str1.valueOf()==str1);//true
- IndexOf(value,start) 查询并返回数据的索引
value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1
var str1 = [12,2,"hello",0,7,0,89];
console.log(str1.indexOf(0))//3
console.log(str1.indexOf(0,-2))//5
- forEach() 参数回调函数,遍历数组的所有项,回调函数接受三个参数,分别是value,index,self.没有返回值。
var str1 = [12,2,"hello",0,7,0,89];
var a = str1.forEach((value,index)=>{
console.log(value+"---"+index)
})
//12---0 2---1 hello---2 0---3 7---4 0---5 89---6
console.log(a)//undefined
- map() 同forEach,同时回调函数返回数据,组成新数组由map返回
var str1 = [12,2,"hello",0,7,0,89];
var a = str1.map((value,index)=>{
console.log(value+"---"+index)
})
//12---0 2---1 hello---2 0---3 7---4 0---5 89---6
var a2 = str1.map((value,index)=>{
return "a2:"+value
})
console.log(a2)//['a2:12', 'a2:2', 'a2:hello', 'a2:0', 'a2:7', 'a2:0', 'a2:89']
console.log(str1)//[12, 2, 'hello', 0, 7, 0, 89]
- filter() 同forEach,同时回调函数返回布尔值,为true的数组组成新数组由filter返回
var str1 = [12,2,"hello","qww","www"];
var a = str1.filter((value,index)=>{
console.log(value+"---"+index)
})
//12---0 2---1 hello---2 qww---3 www---4
var a2 = str1.filter((value,index)=>{
return value.length>0
})
console.log(a2)// ['hello', 'qww', 'www']
console.log(str1) // [12, 2, 'hello', 'qww', 'www']
2.vue2与vue3的组件通信
vue2
父组件向子组件传递数据
- props 父组件通过v-bind发送数据,子组件通过props接收数据
父组件:
<template>
<div>
<Child :msg="1212"></Child>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
};
</script>
子组件:
<template>
<div>
{{msg}}
</div>
</template>
<script lang="ts">
export default {
name: 'Child',
props:['msg']
};
</script>
子传父
- $emit/v-on 子组件可以通过emit发布一个事件并传递一些参数,父组件通过v-on进行这个事件的监听
父组件:
<template>
<div>
<Child :msg="total" v-on:update:msg="total=$event"/>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
data() {
return { total: 10000 };
},
};
</script>
子组件:
<template>
<div>
{{msg}}
<button @click="$emit('update:msg',msg-100)">
<span>-100</span>
</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Child',
props:['msg']
};
</script>
双向绑定
- .sync 修饰符可以实现子组件与父组件的双向绑定,并且可以实现子组件同步修改父组件的值。
<Child :msg.sync="total" /> 等价于 <Child :msg="total" v-on:update:msg="total=$event"/>
<Child :msg="total" v-on:update:msg="total=$event"/>
变成
<Child :msg.sync="total" />
- v-model 和 .sync 类似,可以实现将父组件 通过 v-model 传给子组件,子组件通过 的数据为双向绑定,子组件通过 $emit 修改父组件的数据
父组件:
<template>
<div>
<Child v-model:value="msg"/>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
data() {
return { msg: 10000 };
},
};
</script>
子组件:
<template>
<div>
<input ref="input" :value="value" @input="$emit('update:value', $event.target.value)" />
</div>
</template>
<script lang="ts">
export default {
props:['value'],
};
</script>
父组件访问子组件
- ref $refs可以直接获取元素属性,同时也可以直接获取子组件实例
父组件
<template>
<div>
<Child ref="child"/>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
mounted() {
//获取子组件属性
const child = this.$refs.child
console.log(child.name)
child.someMethod('调用了子组件方法')
}
};
</script>
子组件
<template>
<div>
</div>
</template>
<script lang="ts">
export default {
props:['value'],
data(){
return{
name:'张三'
}
},
methods:{
someMethod(msg){
console.log(msg)
}
}
};
</script>
- $attars
子组件使用attrs"
- $listenters
子组件使用$listeners可以获得父组件(不含.native修饰器的)所有v-on事件监听器,在Vue3中已经不再使用;但是Vue3中的attrs不仅可以获得父组件传来的属性也可以获得父组件v-on事件监听器
父组件
<template>
<div>
<Child @clickF="clickF" :name="name"/>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
data(){
return{
name:'张三'
}
},
methods:{
clickF(val){
console.log(`父组件方法调被用,获取子组件:${val}`)
}
}
};
</script>
子组件
<template>
<div>
<button @click="getClickF">调用父组件方法</button>
</div>
</template>
<script >
export default {
// props:['name'],
mounted(){
console.log(this.$attrs)
console.log(this.$listeners)
},
methods:{
getClickF(){
this.$listeners.clickF('我是子组件数据')
}
}
};
</script>
- provide / inject 爷传给孙的数据
provide:是一个对象,或者是一个返回对象的函数。里面包含要给子孙后代属性
inject:一个字符串数组,或者是一个对象。获取父组件或更高层次的组件provide的值,既在任何后代组件都可以通过inject获得
父组件:
<template>
<div>
<Child :name="name" />
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
data(){
return{
name:'张三'
}
},
provide(){
return{
name:this.name
}
}
};
</script>
子组件:
<template>
<div>
</div>
</template>
<script >
export default {
inject:['name'],
created() {
console.log(this.name)
}
};
</script>
- parent / children
$parent 子组件获取父组件实例对象,可以直接拿到数据和方法对象。
$children 父组件获取子组件的实例,可以直接拿到数据和方法对象。
父
<template>
<div>
{{name}}
<Child :name="name" />
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {Child},
data(){
return{
name:'张三'
}
},
};
</script>
子
<template>
<div>
<button @click="setName">点击修改父组件name</button>
</div>
</template>
<script >
export default {
props:['name'],
methods:{
setName(){
this.$parent.name='历史'
}
}
};
</script>
methods:{
change(){
console.log('==>',this.$children)
}
}
- eventBus 兄弟组件通信可以通过一个事件中心EventBus实现,既新建一个Vue实例来进行事件的监听,触发和销毁。
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
import Vue from "vue"
export default new Vue()
// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
// 方法三 注入到 Vue 根对象上
// main.js
import Vue from "vue"
new Vue({
el:"#app",
data:{
Bus: new Vue()
}
})
// 在需要向外部发送自定义事件的组件内
<template>
<button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
Bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
mounted(){
// 监听事件的触发
Bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
Bus.$off("sendMsg")
}
}
vuex的核心属性有哪些
- 核心应用是 store(仓库),它包含大部分的状态(state)
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
// 定义一个name,以供全局使用
name: '张三',
// 定义一个number,以供全局使用
number: 0,
// 定义一个list,以供全局使用
list: [
{ id: 1, name: '111' },
{ id: 2, name: '222' },
{ id: 3, name: '333' },
],
},
});
export default store;
状态管理的五大核心:state,mutation,action,module,getter.
- state 存放数据,相当于vue里面的 data
- mutations 同步提交更新state里面的数据
修改store/index.js 提交更新可以使用 $store.commit()
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
name: '张三',
number: 0,
},
mutations: {
// 增加nutations属性
setNumber(state) {
// 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数
state.number = 5;
},
},
});
export default store;
修改 app.vue 通过 this.$store.commit
<script>
export default {
mounted() {
console.log(`旧值:${this.$store.state.number}`);
this.$store.commit('setNumber');
console.log(`新值:${this.$store.state.number}`);
},
};
</script>
以上是简单实现mutations的方法,没有传参;如果我们想不固定传参,下面可以看看
修改store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
name: '张三',
number: 0,
},
mutations: {
setNumber(state) {
state.number = 5;
},
setNumberIsWhat(state, number) {
// 增加一个带参数的mutations方法
state.number = number;
},
},
});
export default store;
修改app.vue
<script>
export default {
mounted() {
console.log(`旧值:${this.$store.state.number}`);
this.$store.commit('setNumberIsWhat', 666);
console.log(`新值:${this.$store.state.number}`);
},
};
</script>
- getters 在 state 中的数据基础上进一步对数据加工,与组件的computed一样
在store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
name: '张三',
number: 0,
list: [
{ id: 1, name: '111' },
{ id: 2, name: '222' },
{ id: 3, name: '333' },
],
},
// 在store对象中增加getters属性
getters: {
getMessage(state) {
// 获取修饰后的name,第一个参数state为必要参数,必须写在形参上
return `hello${state.name}`;
},
},
});
export default store;
在app.vue中
export default {
mounted() {
// 注意不是$store.state了,而是$store.getters
console.log(this.$store.state.name);
console.log(this.$store.getters.getMessage);
},
};
- actions 异步修改数据
const store = new Vuex.Store({
state:{
name:'张三',
number:0,
},
mutations:{
setNumberIsWhat(state,payload){
state.name = payload.number;
}
},
actions:{
//增加actions 的属性
setName(content){
//增加setName方法,默认第一个参数content,其值是复制的一份store
return new Promise(resolve => {
//我们模拟一个异步操作,1秒后修改number ,为888
setTimeout(()=>{
content.commit('setNumberIsWhat',{number:888});
resolve()
},1000),
})
}
}
})
修改 App.vue
async mouted(){
console.log(`旧值:${this.$store.state.number}`);
await this.$store.dispatch('setName');
console.log(`新值:${this.$store.state.number}`);
}
-
module 按功能进行拆分模块
新增一个新的仓库store2
// store2.js
const store2 = {
state: {
name: '我是store2',
},
mutations: {},
getters: {},
actions: {},
};
export default store2;
在store中引入我们新创建的store2模块
import Vue from 'vue';
import Vuex from 'vuex';
import { state } from './state';
import { getters } from './getters';
import { mutations } from './mutations';
import { actions } from './actions';
import store2 from './store2'; // 引入store2模块
Vue.use(Vuex);
const store = new Vuex.Store({
modules: { store2 }, // 把store2模块挂载到store里面
state: state,
getters: getters,
mutations: mutations,
actions: actions,
});
export default store;
访问state - 我们在App.vue测试访问store2模块中的state中的name
<template>
<div></div>
</template>
<script>
export default {
mounted() {
console.log(this.$store.state.store2.name); // 访问store2里面的name属性
},
};
</script>
mixins 类似于公共的方法,减少重复
局部单页面混入 新建mixins.js页面
const myMixins = {
data(){
return{
isNoData:false,
isShow:true,
}
}
}
export dafault myMIxin;
在需要引入的页面中注册
import Minix form '@/components/Mixin/index.js'
export default{
minxins;[Minix],
}
全局混入 在main.js 中注册引用
import Minix form '@/components/Mixin/index.js'
Vue.mixin(mixin)
$nextTick() 在下次DOM异步更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM
视图已经更新,dom还没有更新
守卫导航
全局守卫
- 路由进入之前 router.beforeEach
- 路由离开之后 router.afterEach
// main.js 入口文件
import router from './router'; // 引入路由
router.beforeEach((to, from, next) => {
next();
});
router.beforeResolve((to, from, next) => {
next();
});
router.afterEach((to, from) => {
console.log('afterEach 全局后置钩子');
});
深拷贝与浅拷贝的理解
浅拷贝:创建一个新对象,这个拷贝对象有着原始对象的属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝就是内存地址。如果其中一个对象改变了地址,就会影响到另一个对象。
深拷贝:创建一个新对象和数组,将值和地址复制给拷贝对象,可以无限层级拷贝,深拷贝后的对象不会和拷贝对象互相影响。
赋值
const obj = {
name: 'lin'
}
const newObj = obj
obj.name = 'xxx' // 改变原来的对象
console.log('原来的对象', obj)
console.log('新的对象', newObj)
console.log('两者指向同一地址', obj == newObj)
//原来的对象 {name: 'xxx'}
//新的对象 {name: 'xxx'}
//两者指向同一地址 true
浅拷贝
- Object.assign({},object)
const person = {
name:'zs',
hobby: { like: 'running' }
}
let newPerson = Object.assign({},person)
newPerson.name='ls'
newPerson.hobby.like = 'singing'
console.log(newPerson)//hobby: {like: 'singing'} name: "ls"
//对比原数据,基本类型数据没有影响,数据类型地址改变,影响原数据
console.log(person)// hobby: {like: 'singing'} name: "zs"
- 扩展运算符(...) 类似于 Object.assign({},object)
- 拷贝对象
const person = {
name:'zs',
hobby: { like: 'running' }
}
let newPerson ={...person}
newPerson.name='ls'
newPerson.hobby.like = 'singing'
console.log(newPerson)//hobby: {like: 'singing'} name: "ls"
//对比原数据,基本类型数据没有影响,数据类型地址改变,影响原数据
console.log(person)// hobby: {like: 'singing'} name: "zs"
- 拷贝数组
const person = ['name','hobby','person',{age:20}]
let newPerson =[...person]
newPerson[0] = 'newName'
newPerson[person.length-1].age = 30
//["newName","hobby","person",{age: 30}]
console.log(person)
//对比原数据,基本类型数据没有影响,数据类型地址改变,影响原数据
//["name","hobby","person",{age: 30}]
- Array.prototype.concat()
let myArr = ['old', null, undefined, true,{ hobby: 'undefined' } ]
hobby: undefined
}];
let copyMyarr1 = myArr.concat();
copyMyarr1[0] = 'nickname';
copyMyarr1[copyMyarr1.length - 1].hobby = 'books'
console.log(copyMyarr1); //[ 'nickname', null, undefined, true, { hobby: 'books' } ]
//对比原数据,数组copyMyarr1的改变影响了数组myArr的改变
console.log(myArr); //[ 'old', null, undefined, true, { hobby: 'books' } ]
- Array.prototype.slice()
let myArr = ['old', null, undefined, true, {
hobby: undefined
}]; //原数据[ 'old', null, undefined, true, { hobby: 'undefined' } ]
let copyMyarr2 = myArr.slice();
copyMyarr2[0] = 'nickname';
copyMyarr2[copyMyarr2.length - 1].hobby = 'books'
console.log(copyMyarr2); //[ 'nickname', null, undefined, true, { hobby: 'books' } ]
//对比原数据,数组copyMyarr2的改变影响了数组myArr的改变
console.log(myArr); //[ 'old', null, undefined, true, { hobby: 'books' } ]
深拷贝
const obj = JSON.parse(JSON.stringity())
缺点:
- 不支持 Date、正则、undefined、函数等数据
- 不能拷贝循环引用的对象
- 使用递归的方式进行对象(数组)的深拷贝
//函数拷贝
const copyObj = (obj = {}) => {
//变量先置空
let newobj = null;
//判断是否需要继续进行递归
if (typeof (obj) == 'object' && obj !== null) {
newobj = obj instanceof Array ? [] : {};
//进行下一层递归克隆
for (var i in obj) {
newobj[i] = copyObj(obj[i])
}
//如果不是对象直接赋值
} else newobj = obj;
return newobj;
}
//模拟对象
let obj = {
numberParams:1,
functionParams:() => {
console.log('昨天基金全是绿的,只有我的眼睛是红的');
},
objParams:{
a:1,
b:2
}
}
const newObj = copyObj(obj); //这样就完成了一个对象的递归拷贝
obj.numberParams = 100; //更改第一个对象的指
console.log(newObj.numberParams); //输出依然是1 不会跟随obj去改变