Mixin和Vuex
- Vuex公共状态管理,如果在一个组件中更改了Vuex中的某个数据,那么其它所有引用了Vuex中该数据的组件也会跟着变化。
- Mixin中的数据和方法都是独立的,组件之间使用后是互相不影响的。
1、定义一个混入(mixin)
在我们的项目src目录下新建mixin文件夹,然后新建index.js文件,该文件存放我们的mixin代码。
// src/mixin/index.js
export const mixins = {
data() { return {}; },
computed: {},
created() {},
mounted() {},
methods: {},
};
2、在组件中使用
import myMixins from "../mixins"; //导入混入(mixin)
mixins: [myMixins] //使用混入(mixin)
v-model和.sync的区别
v-mode
是Vue.js提供的一个语法糖指令,用于在表单元素上实现双向数据绑定。它会自动监听输入框、下拉框、单选框等表单元素的值变化,并将其更新到Vue实例的数据中,同时,当Vue实例数据发生改变时,也会将新的值反映到表单元素上。它的语法如下:
<input v-model="message">
.sync修饰符
<!-- 父组件 -->
<template>
<child-component :message.sync="message"></child-component>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
updateMessage(newValue) {
this.message = newValue;
}
},
components: {
ChildComponent
}
}
</script>
<!-- 子组件 -->
<template>
<input :value="message" @input="$emit('update:message', $event.target.value)">
</template>
父组件向子组件传递了一个message
属性,并使用.sync
修饰符,这样父组件会自动监听子组件触发的update:message
事件,并在触发时更新父组件中的message
属性。
合理拆分store并配置全局getter
示例:
正常访问方式如下:
this.$store.state.user.userInfo.skill.info.age // 18
使用全局getters优化
export defaut{ age: state => state.user.userInfo.skill.info.age -> 18 }
// 使用全局getters快捷访问方式,如下:
this.$store.gettes.age -> 18
组件中调用action发请求的流程
页面跳转传值的方式-query¶ms
声明式导航的两种方式:
(1)query
to=“/path?参数名=值&参数名2=值” 接收传值:$route.query.参数名
(2)params
路由的路径中 routes: [ …,{ path: ‘/search/:words?’, component: Search } ] }) 接收传值:$route.params.参数名
声明式导航的两种方式:
(1)query
this.$router.push('/路径?参数名1=值&参数2=值')
/this.$router.push({ path: '/路径',query:{ 参数名1: '值',参数名2: '值' } })
/this.$router.push({ name: '路由名字',query: {参数名1: '值',参数名2: '值' } }) //name跳转
接收传值:**$route.query.参数名**
(2)params
this.$router.push('/路径/参数值')
/this.$router.push({ path: '/路径/参数值' })
/this.$router.push({name: '路由名字',params: { 参数名: '参数值', } })
接收传值:**$route.params.参数名**
组件之间传值的方式
(1)父传子
//父组件
<template>
<div>
++ <son :data='name'></son>
</div>
</template>
<script>
++ import son from "./son.vue";//导入子组件
export default {
++ components: { son },//注册组件
name: "父组件",
data() {
return {
name: "Frazier", //父组件定义变量
};
},
};
</script>
//子组件
<template>
<div>{{data}}</div>
</template>
<script>
export default {
components: { },
name: '子组件',
++ props:["data"],
};
</script>
(2)子传父
//子组件
<template>
<div>
<button @click="lcalter">点我</button>
</div>
</template>
<script>
export default {
...
methods: {
lcalter(){
++ this.$emit('lcclick')//通过emit来触发事件
}
},
};
</script>
//父组件
<template>
<div>
++ <son @lcclick="lcclick"></son>//自定义一个事件
</div>
</template>
<script>
...
methods: {
lcclick(){
alert('子传父')
}
},
};
</script>
(3)兄弟组件通信(bus总线)
(1)在src中新建一个Bus.js的文件,然后导出一个空的vue实例
(2)在传输数据的一方引入Bus.js 然后通过Bus.e m i t ( “ 事 件 名 ” , " 参 数 " ) 来 来 派 发 事 件 , 数 据 是 以 emit(“事件名”,“参数”)来来派发事件,数据是以emit(“事件名”,“参数”)来来派发事件,数据是以emit()的参 数形式来传递
(3)在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on(“事件名”,(data)=>{data是接受的数据})
1、新建bus.js,并引用
/**bus.js**/
import Vue from 'vue'
const bus = new Vue()
export default bus
2、在A组件页面里
<template>
<div class="components-a">
<button @click="abtn">A按钮</button>
</div>
</template>
<script>
++import bus from '@/assets/bus.js';
export default {
data () {
return {
‘msg':"我是组件A"
}
},
methods:{
abtn(){
++ eventVue.$emit("myFun",this.msg) //$emit这个方法会触发一个事件
}
}
}
</script>
3.在B组件:
<template>
<div class="components-a">
<div>{{btext}}</div>
</div>
</template>
<script>
++import bus from '@/assets/bus.js';
export default {
name: 'app',
data () {
return {
'btext':"我是B组件内容"
}
},
created(){
this.bbtn();
},
methods:{
bbtn(){
++ eventVue.$on("myFun",(message)=>{ //这里最好用箭头函数,不然this指向有问题
++ this.btext = message
})
}
}
}
</script>
(4)ref/refs(父子组件通信)
父组件通过ref/refs调用子组件方法
//父组件
<template>
<div>
<button @click="sayHello">sayHello</button>
<child ref="childForRef"></child> //子组件
</div>
</template>
<script>
import child from './child.vue' //引入子组件
export default {
components: { child }, //注册子组件
...
methods: {
sayHello() {
++ this.$refs.childForRef.sayHello() //调用子组件方法
}
}
}
</script>
//子组件
<template>
<div>child 的内容</div>
</template>
<script>
export default {
...
methods: {
++ sayHello () {
console.log('hello');
}
}
}
</script>
(5)全局变量
定义一个全局变量,在有值的组件直接赋值,在需要的组件内直接使用就可以了
在main里面注册组件
//全局组件
import MyList from './components/MyList.vue'
Vue.component(MyList.name,MyList)
在要引入的组件写上 name: “LoginName”,
<LoginName ref="login"></LoginName>
全局变量第二种方法:
在Vue实例之外定义一个全局变量,例如在main.js或单独的一个文件中:
// main.js 或单独的一个文件,例如 globals.js
// 定义全局变量
Vue.prototype.$myGlobalVariable = '这是一个全局变量';
在需要使用该全局变量的组件中,可以直接引用并使用它:
<template>
<div>
<!-- 直接使用全局变量 -->
<p>{{ $myGlobalVariable }}</p>
</div>
</template>
<script>
export default {
name: 'MyComponent',
mounted() {
// 可以在组件内部直接使用全局变量
console.log(this.$myGlobalVariable);
}
}
</script>
(6)promise传参
promise 中 resolve 如何传递多个参数
//类似与这样使用,但实际上后面两个参数无法获取
promise = new Promise((resolve,reject)=>{
let a = 1
let b = 2
let c = 3
resolve(a,b,c)
})
promise.then((a,b,c)=>{
console.log(a,b,c)
})
resolve() 只能接受并处理一个参数,多余的参数会被忽略掉。
如果想多个用数组,或者对象方式。
数组
promise = new Promise((resolve,reject)=>{
resolve([1,2,3])
})
promise.then((arr)=>{
console.log(arr[0],arr[1],arr[2])
})
对象
promise = new Promise((resolve,reject)=>{
resolve({a:1,b:2,c:3})
})
promise.then(obj=>{
console.log(obj.a,obj.b,obj.c)
})
(7)$parent
// 获父组件的数据
this.$parent.foo
// 写入父组件的数据
this.$parent.foo = 2
// 访问父组件的计算属性
this.$parent.bar
// 调用父组件的方法
this.$parent.baz()
//在子组件传给父组件例子中,可以使用this.$parent.getNum(100)传值给父组件。
(8)Vuex通信
组件通过 dispatch 到 actions,actions 是异步操作,再 actions中通过 commit 到 mutations,mutations 再通过逻辑操作改变 state,从而同步到组件,更新其数据状态
$nextTick
用于在下一次DOM更新循环结束后执行回调函数。
1.在created中进行dom操作
使用原因 : created()执行的时候DOM还未进行任何渲染。
<template>
<div class="hello">
<button ref="text">{{ msg }}</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
msg: '我是按钮的文字',
}
},
created() {
console.log(this.$refs.text.innerHTML)
that.$nextTick(function () {
console.log(this.$refs.text.innerHTML) //我是按钮的文字
})
},
}
</script>
2.重置组件的操作
<template>
<div>
<my-tick v-if="show" />
<button @click="reset">重置</button>
</div>
</template>
<script>
import MyTick from './components/MyTick.vue'
export default {
components: { MyTick },
data() {
return {
show: true,
}
},
methods: {
reset() {
// 刷新: 先移除 再添加
// vue的设计: 方法执行到结尾, 把最终的效果更新DOM, 所以false没执行
// 原生DOM: 每行代码的执行都会刷新DOM
this.show = false
// 在本次渲染完毕后, 立刻执行下一个任务: nextTick
this.$nextTick(() => (this.show = true))
//$nextTick: 在本次渲染结束后的下一次渲染中, 例如执行 true 的操作
},
},
}
</script>
3.获取更新后的DOM元素的尺寸或位置
mounted() {
this.$nextTick(() => {
// 这里可以执行DOM相关的操作,例如获取更新后的DOM元素
const element = document.getElementById('my-element');
const elementWidth = element.offsetWidth;
});
}
4.异步更新后的回调,例:在数据获取、API调用等完成后进行一些更新数据、操作DOM等的操作
methods: {
fetchData() {
// 异步获取数据
fetchDataAsync().then((data) => {
// 更新数据
this.data = data;
// 在DOM更新后执行回调函数
this.$nextTick(() => {
// 这里可以执行一些操作,例如处理数据、更新DOM等
this.processData();
});
});
},
processData() {
// 处理数据
// ...
}
}
5.页面刷新之后,input框获取焦点
6.组件之间的通信
当父组件修改了传递给子组件的props,并希望在子组件中立即响应这些变化时,可以使用$nextTick
来确保在DOM更新后再进行操作。
<template>
<div>
<button @click="changeValue">Change Value</button>
<child-component :value="propValue" @value-updated="handleValueUpdated"></child-component>
</div>
</template>
<script>
export default {
data() {
return {
propValue: 'Initial Value'
};
},
methods: {
changeValue() {
this.propValue = 'New Value';
this.$nextTick(() => {
console.log('DOM Updated');
});
},
handleValueUpdated(newValue) {
console.log('Child Value Updated:', newValue);
}
}
};
</script>
<template>
<div>
<p>Value: {{ value }}</p>
</div>
</template>
<script>
export default {
props: ['value'],
watch: {
value(newValue) {
this.$emit('value-updated', newValue);
}
}
};
</script>
$set的应用场景
由于javaScript的限制,vue不能检测除了push,pop,shift等等以外的数组变化
数组:
this.$set(Array, index, newValue)
对象:
this.$set(Object, key, value)
使用vue.use对自定义组件|指令进行快速注册
// 导入所需的自定义组件和指令
import MyComponent from './components/MyComponent.vue';
import MyDirective from './directives/MyDirective';
// 在Vue.use中注册组件和指令
Vue.use({
install(Vue) {
// 注册自定义组件
Vue.component('my-component', MyComponent);
// 注册自定义指令
Vue.directive('my-directive', MyDirective);
},
});
v2响应式的缺陷及对应proxy的优点
在Vue 2中,响应式系统的缺陷主要有以下几个问题:
- 对象新增属性或删除属性无法响应:Vue 2只能在初始化实例时对属性进行响应式处理,后续新增的属性或删除的属性无法实时触发更新。
- 数组索引和length的响应性问题:Vue 2无法检测到直接通过索引或修改length的方式进行的数组变动,需要使用特定的变异方法(如push、pop等)才能响应变化。
- **深层属性的监听问题:**Vue 2默认只能响应对象的一层属性变化,无法递归地监听嵌套对象的属性变化。
下面是使用Proxy实现响应式的优点的示例代码:
// 创建响应式对象
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
// 返回属性值
return Reflect.get(target, key);
},
set(target, key, value) {
// 更新属性值
Reflect.set(target, key, value);
// 执行触发更新的操作
// ...
},
deleteProperty(target, key) {
// 删除属性
Reflect.deleteProperty(target, key);
// 执行触发更新的操作
// ...
}
});
}
// 创建响应式对象
const obj = reactive({ count: 0 });
console.log(obj.count); // 输出: 0
// 更新属性值
obj.count = 1;
console.log(obj.count); // 输出: 1
// 删除属性
delete obj.count;
console.log(obj.count); // 输出: undefined
// 创建响应式对象
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
// 返回属性值
return Reflect.get(target, key);
},
set(target, key, value) {
// 更新属性值
Reflect.set(target, key, value);
// 执行触发更新的操作
// ...
},
deleteProperty(target, key) {
// 删除属性
Reflect.deleteProperty(target, key);
// 执行触发更新的操作
// ...
}
});
}
// 创建响应式对象
const obj = reactive({ count: 0 });
console.log(obj.count); // 输出: 0
// 更新属性值
obj.count = 1;
console.log(obj.count); // 输出: 1
// 删除属性
delete obj.count;
console.log(obj.count); // 输出: undefined