vue高阶
rem移动端适配
(1)元素单位有哪些
1.px(像素)
2.百分比
3…vh和vw
4.em和rem都是相对大小
rem是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素
vue项目配置rem
1.安装插件
npm i amfe-flexible --save
2.在main.js导入 import 'amfe-flexible"
3.px自动转rem
安装插件npm i postcss-pxtorem@5.1.1
在、vue.config.js添加px2rem插件,把项目中的px转为rem
4.插件会修改html和body的字体大小,而字体会继承,所以要重新设置body的font-size为合适的字体大小
const pxtorem = require("postcss-pxtorem");
module.exports = {
css: {
loaderOptions: {
// 后处理器配置
postcss: {
postcssOptions: {
plugins: [
// 把px转为rem
pxtorem({
rootValue: 37.5,
propList: ["*"],
unitPrecision: 4, //保留rem小数点多少位
})
]
}
}
}
}
};
vue mixin是什么
mixin其实是一个对象,里面的结构大致跟普通组件的script里面的一样,有data属性,钩子函数和方法混入(minxins)是一种分发Vue组件可复用功能的非常灵活的方式.混入对象可以包含任意组件选项.当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项.
作用:可以用来提取多个组件中的共同属性和方法等
01组件内混入
(1).混入对象的生命周期先执行
(2)data里面的状态若有重名,取得是组件里面的状态(就近原则)
//home.vue
<template>
<div>home</div>
</template>
<script>
import mixin from "./mixin"
export default {
data(){
return{
list : "父组件的值"
}
},
mixins:[mixin],
created(){
console.log(this.list);
}
}
</script>
//mixin.js
export default{
data(){
return {
list : "我是mixin的信息"
}
}
}
(2)全局混入
1.创建
2.混入
3.使用
当父组件中没有这个方法,但是mixin的文件中有这个方法,我们在父组件中也可以使用这个方法
//home.vue
<template>
<div>home</div>
</template>
<script>
import mixin from "./mixin"
export default {
data(){
return{
list : "父组件的值"
}
},
mixins:[mixin],
created(){
this.text();
}
}
</script>
//mixin.js
export default{
data(){
return {
list : "我是mixin的信息"
}
},
methods:{
text(){
console.log("mixin的事件");
}
}
}
nextTick获取更新后的dom
在vue中,修改了数据,dom是异步更新的,所以当修改了数据,立即去获取dom节点,你获取的并不是更新后IDEdom,如果你想获取更新后的dom,可以使用nextTick,这个函数是在dom更新后立刻执行,(可以获取到我们更新后的标签以及数据)
<template>
<div><span ref="text">{{msg}}</span><button @click="myfunc">修改</button></div>
</template>
<script>
export default {
data(){
return{
msg:"小编是个帅哥"
}
},
methods:{
myfunc(){
this.msg="小编嘎嘎帅气";
console.log(this.$refs.text.innerText);
this.$nextTick(()=>{
console.log(this.$refs.text.innerText);
})
}
}
}
</script>
ref获取原生dom节点和组件实例
(1).获取原生dom节点和子组件实例
需要注意的地方:
1.只在组件渲染完后才能填充,所以created()无法访问,mounted()可以访问
2.$refs不是响应式的,所以,子组件状态的改变并不能让父组件的状态也跟着发生改变
//home.vue
<template>
<div>
父组件
<hr>
<child ref="cc"/>
</div>
</template>
<script>
import child from "./child.vue"
export default {
data(){
return {
father:{}
}
},
created(){
console.log(this.$refs);
},
mounted(){
this.father=this.$refs.cc.msg;
console.log(this.$refs.cc);
},
components:{
child
}
}
</script>
//child.vue
<template>
<div>
<input type="text" v-model="msg">
</div>
</template>
<script>
export default {
data(){
return {
msg:''
}
}
}
</script>
Vue中computed和watch的区别
(1).计算属性computed:
1.支持缓存,只有依赖数据发生改变,才会重新进行计算
<template>
<div>
<p>{{counted}}</p>
<p>{{counted}}</p>
<p>{{counted}}</p>
<hr>
<p>{{computcc(2)}}</p>
<p>{{computcc(2)}}</p>
<p>{{computcc(2)}}</p>
<p>{{computcc(2)}}</p>
</div>
</template>
<script>
export default {
data(){
return {
counte:10
}
},
computed:{
counted(){
console.log("countes");
return this.counte*20
},
},
methods:{
computcc(counte){
console.log("computcc");
return counte+10
}
}
}
</script>
2.不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4.如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.在computed中的,属性都有一个get和set方法,当数据变化时,调用set方法
<template>
<div>
<p>{{counte}}<button @click="counte1">修改</button></p>
<p>{{counte}}<button @click="counte2='40'">修改</button></p>
</div>
</template>
<script>
export default {
data(){
return{
counte:10
}
},
computed:{
counte2:{
get(){
console.log("get");
},
set(value){
console.log('set');
this.counte=value;
}
}
},
methods:{
counte1(){
this.counte=this.counte*5
},
}
}
</script>
侦查属性watch:
1.不支持缓存,数据变,直接会触发相应的操作
2.watch支持异步
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值
4.当一个属性发生变化时,需要执行对应的操作,一对多;
5.watch的高级用法
1.watch的一般用法,修改对象属性不会触发watch,给对象重新赋值会触发watch
<template>
<div>
<p>{{obj.username}}<button @click="obj.username='小帅哥'">修改</button></p><!-- 这个直接修改了对象的属性没有触发watch监听 -->
<p>{{obj.username}}<button @click="myfunc">修改</button></p>
</div>
</template>
<script>
export default {
data(){
return {
obj:{
username:'小编'
}
}
},
watch:{
obj(newobj,oldobj){
console.log("调用了");
console.log(newobj);
}
},
methods:{
myfunc(){
this.obj={
username:'小帅哥'
}
}
}
}
</script>
2.watch的一个方法两个属性
handleer方法
deep属性 深层监听
immediate属性 一开始就执行一次
<template>
<div>
<li v-for="(item, index) in list" :key="index" class="mt-10">
<span>{{ item.name }}</span>
<van-button
class="ml-10"
@click="update(item)"
type="danger"
>修改</van-button
>
</li>
<button @click="update">修改</button>
</div>
</template>
<script>
export default {
data() {
return {
list: [{ name: "张三" }, { name: "张四" }, { name: "张五" }],
};
},
watch: {
list: {
// 监听的对象发生变化时, 触发此函数
handler(newValue, oldValue) {
console.log(newValue, oldValue);
},
// deep 深层监听
deep: true,
// 一开始就执行一次
immediate: true
},
},
methods: {
update(item) {
item.name = item.name + "广东";
},
},
};
</script>
(十一) 父子组件双向数据绑定
**(1) 父子组件通信注意点
- 父组件传数据给子组件, 子组件收到数据, 不可以直接修改数据, 否则会报错
- 子组件要修改父组件传过来的数据, 需要父组件自定义事件, 子组件$emit(自定义事件名称)
- 第1和第2点, 数据流动的都只有一个方向, 称为单向数据流
**(2) 父子组件双向数据绑定copy.html
意思是说, 父组件改变数据, 子组件跟着改变, 子组件修改了数据, 父组件也跟着改变, 跟input里的v-model一个意思, 很显然正常的父子组件通信方式来实现数据双向数据绑定是一个比较麻烦的事情
// demo.vue
<template>
<div>
<h3>父组件 {{msg}}</h3>
<hr>
<Son :msg="msg" @aaa="onAaa"/>
</div>
</template>
<script>
import Son from './Son.vue'
export default {
components: {
Son,
},
data() {
return {
msg: 'hello'
}
},
methods: {
onAaa(data) {
this.msg = data;
}
}
};
</script>
// Son.vue
<template>
<div>
<h4>子组件 {{msg}}</h4>
<button @click="$emit('aaa','hello world')">修改数据</button>
</div>
</template>
<script>
export default {
props: ['msg']
}
</script>
**(3) 父子组件双向数据绑定的简化版
// demo.vue
<template>
<div>
<h3>父组件 {{msg}}</h3>
<hr>
<Son :msg.sync="msg"/>
</div>
</template>
<script>
import Son from './Son.vue'
export default {
components: {
Son,
},
data() {
return {
msg: 'hello'
}
}
};
</script>
// Son.vue
<template>
<div>
<h4>子组件 {{msg}}</h4>
<button @click="$emit('update:msg','hello world')">修改数据</button>
</div>
</template>
<script>
export default {
props: ['msg']
}
</script>
|---------常见问题------------|[#](http://zl.huruqing.cn/第05章 Vue2/第4节 Vue进阶知识(1) copy.html#常见问题)
(1) vue组件中的data为什么是一个函数, 并且必须return 一个对象?[#](http://zl.huruqing.cn/第05章 Vue2/第4节 Vue进阶知识(1) copy.html#_1-vue组件中的data为什么是一个函数-并且必须return-一个对象)
答:因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。组件中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
(2) 使用v-for为什么要添加key并且key为什么必须唯一, 而且不推荐使用index做key
https://blog.csdn.net/kiyoometal/article/details/89849345
答:
- 使用v-for更新已渲染的元素列表时,默认用就地复用策略;列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;
- 若使用index作为key, 那么, 如果在数组中间插入一个成员的时候, 数组成员的index会被打乱, 大大影响复用效果
- 如果key发生重复, 那么也会影响复用效果, 就好像有两个人的身份证编号一样的时候, 会造成冲突
(3) v-for和v-if指令为什么不能放在同一个标签上
答: 因为v-for优先级比v-if的优先级高, 如果两个指令放在同一个标签上, 那么在渲染列表的时候, 会对每一个数组成员都进行一次判断, 若值为true显示标签, 值为false不显示标签, 会比较消耗性能, 更好的做法是使用computed或者filter, 先对数组成员进行过滤, 把需要显示的成员过滤出来, 然后再使用v-for指令
// 使用filter
<template>
<div>
<p v-for="(item) in list.filter(item=>item.age>20)" :key="item.id" >{{item.name}}</p>
</div>
</template>
<script>
export default {
data() {
return {
list:[ { name: '张三', age:18, id: '001' }, { name: '张四', age:20, id: '002' },
{ name: '张五', age:22, id: '003', }, { name: '张六', age:24, id: '004' }, ]
}
}
}
</script>
// 使用computed
<template>
<div>
<p v-for="item in list" :key="item.id">{{ item.name }}</p>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ name: "张三", age: 18, id: "001" },
{ name: "张四", age: 20, id: "002" },
{ name: "张五", age: 22, id: "003" },
{ name: "张六", age: 24, id: "004" },
],
};
},
computed: {
list2() {
return this.list.filter((item) => item.age > 20);
},
},
};
</script>