Vue

185 阅读5分钟

Vue

数据代理

  • vm._data=data=options.data
  1. Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
  2. Vue中数据代理的好处:更加方便的操作data中的数据
  3. 基本原理:通过object.defineProperty()把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写)data中对应的属性。
<body>
    <div id="app">
        <h1>{{name}}</h1>
        <h1>{{age}}</h1>
        <h1>{{address}}</h1>
    </div>
    <script>
        Vue.config.productionTip = false;
        let data = {
            name: "wc",
            age: 18,
            address: "zz"
        }
        let vm = new Vue({
            data() {
                return data;
            }
        })
​
        vm.$mount("#app");
    </script>
</body>

数据代理.png

数据劫持.png

虚拟DOM和diff算法

v-if 和v-show的区别

  1. v-if是控制元素的创建或销毁,每次创建出来的都是新的,创建或销毁DOM元素,很耗性能。
  2. v-if后面的条件是false,它是惰性的,DOM元素压根不会创建
  3. v-show后面的条件不管是true或false,DOM元素都会创建,它是通过display来控制元素的显示或隐藏
  4. v-show不支持template标签,v-if支持template标签
  5. v-if会导致浏览器的重排(重排一定会引起重绘),v-show导致浏览器的重绘。
  6. 如果需要频繁控制元素的显示或隐藏,那么使用v-show,不频繁,也可以使用v-if,尽可能使用v-show

自定义指令

    1. 对象写法
    1. 函数写法 相当于对象的简写只写了bind()和update()
    1. 何时调用
    //自定义指令的配置对象 函数写法
                directives: {
                    // 1.模板和自定义指令绑定时  (有了v-big="number")一上来 就执行big();
                    // 2.整个模板的某个数据变了   就执行big()
                    big(element, binding) {
                        //自定义指令所在标签元素
                        console.log(element);
                        //自定义指令对象
                        console.log(binding);
                        element.innerText = binding.value * 10;
                    },
    //自定义指令的配置对象 对象写法
                    fbind: {
                        //1.模板和自定义指令绑定时  (有了v-big="number")一上来 就执行bind();
                        bind(element, binding) {
                            element.value = binding.value
                        },
                        //2.指令所在元素插入页面时
                        inserted(element, binding) {
                            element.focus();
                        },
                        //3.指令所在模板被重新解析时
                        update(element, binding) {
                            element.value = binding.value
                        }
                    }
                }
    

数组更新检测

在模型中数据是数组时,此时的数组元素被修改时不一定是响应式的

  • 不是响应式的
  1. 通过中括号修改数组
  2. 通过修改数组长度修改数组
  • 是响应式的

数组的方法

  1. push("item","item",.......): 在数组后面添加n个元素;并返回添加后的数组长度
  2. pop():删除数组的最后一个元素,并返回被删除的(即最后一个元素)内容;空数组返回und
  3. shift():删除数组的第一个元素,并返回被删除的(即最后一个元素)内容;空数组返回und
  4. unshift(item1,item2,.....): 在数组前面添加n个元素;并返回添加后的数组长度
  5. splice(index,num,item1,item2,...)index开始删除/添加元素的下标,num从下标开始(包含下标)要从前往后删除的几个元素,item从下标开始(包含下标)要从前往后添加的元素.返回包含被删除的所有元素的数组,没有删除就返回空数组
  6. sort(function(a,b)=>{return a-b}):升序 sort(function(a,b)=>{return b-a}):降序 返回一个包含排序后所有数组元素的数组对象 (3) [22, 33, 44, ob: Observer]
  1. reverse()反转数组:返回一个包含反转后所有数组元素的数组对象 (3)['打豆豆', '睡觉', '吃饭', ob: Observer]

路由配置

  1. 利用Hash   (利用锚点(a标签)实现hash值的改变,通过hashchange事件监听location.hash的变化,使得对应的url现实不同的内容)
  2. 利用history Api (pushState方法,popstate事件类型)
  3. vue-router

vue-router

配置步骤

  1. 安装Vue Router:npm install vue-router@3.5.3

路由配置.png

过滤器

通常用来格式化 视图中的第一个作为实参传入,返回值作为下一个函数的参数 可以一直通过 | (管道符) 一直向后传递过滤

<template> 
  <div>
    <!-- 使用过滤器,需要对time时间进行格式化,进行过滤 -->
    <h1>{{ time | timeFormat }}</h1>   
  </div>
</template><script>
// 引入moment  moment是专门用来处理时间
import moment from "moment";
export default {
  name: "MyComponent1",
  props: [],
  data() {
    return {
      time: Date.now(),
    };
  },
  methods: {},
   // 在filters选项中,可以配置局部过滤器
   // 在这里配置的局部过滤器,只能在当前组件中使用
    filters: {
        // 定义了一个过滤器,叫timeFormat
        // 在模板中,就可以使用过滤器了
        timeFormat(params){
           //利用moment对时间进行格式化
            return 666;
            //需要return一个格式化后的时间
           return moment(params).format("YYYY-MM-DD")
         }
     },
};
</script>

生命周期

生命周期.png

动态组件 & keep-alive组件

  • 动态组件

    • 根据 :is="组件名" 渲染对应组件 (定义一个状态直接可以把组件名放进去 模板中直接读取 就能找到对应的组件去渲染)
    • 组件来回切换时 频繁销毁创建
    • 用于tab栏切换
  • keep-alive

    • 注意这个 <keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
    • 组件实例能够被在它们第一次被创建的时候缓存下来 提高性能 还能保持组件的状态 (被选中的文章) 甚至当它未被渲染时也是如此
    • keep-alive生命周期钩子 (activated )在keep-alive组件激活时调用 , (deactivated )在keep-alive组件停用时调用
    • 使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务。
    • 该钩子在服务器端渲染期间不被调用
//App组件
<template>
  <div>
    <button @click="HandleHome">主页</button>
    <button @click="HandleLogin">登录</button>
    <keep-alive>
      <component :is="componentId"></component>
    </keep-alive>
  </div>
</template><script>
import Home from "./components/home.vue"
import Login from "./components/login.vue"
export default {
  name: 'App',
  components: {
    Home,
    Login
  },
  data() {
    return {
        //定义一个状态直接可以把组件名放进去  模板中直接读取 就能找到对应的组件去渲染
      componentId: "Home"
    };
  },
  computed: {
​
  },
  methods: {
    //点击按钮 更换组件
    HandleHome() {
      this.componentId = "Home"
    },
    HandleLogin() {
      this.componentId = "Login"
    }
  }
}
</script>
​
​
//Home组件
<template>
    <div>
        <span>我是主页面</span>
    </div>
</template><script>
export default {
    created() {
        console.log("组件创建了");
    },
    destroyed() { 
        console.log("组件销毁了");
    },
    activated(){
        console.log("在keep-alive 组件激活时调用");    
    },
    deactivated(){
        console.log("在 keep-alive 组件停用时调用");    
    },
}
</script>
​
//Login 组件
<template>
    <div>
        <span>我是登录页</span>
    </div>
</template><script>
export default {
    created() {
        console.log("组件创建了");
    },
    destroyed() {
        console.log("组件销毁了");
    },
}
</script>

vue监测对象 (响应式对象原理简单模拟) 源码复杂得多

  • 创建监测对象 防止set get 递归调用
<script type="text/javascript">
        let data = {
            name: "汉库克",
            address: "女儿国"
        }
​
        function Observer(obj) {
            //转对象为数组
            let keys = Object.keys(obj)
​
            //this 是  obs
            keys.forEach((k) => {
                Object.defineProperty(this, k, {
                    get() {
                        return obj[k]
                    },
                    set(val) {
                        obj[k] = val
                    }
                })
            })
        }
        //创建监测对象
        let obs = new Observer(data)
​
        let vm = {}
​
        vm._data = data = obs
​
        console.log(vm._data);
    </script>

mixin (混入)

复用代码

  • 全局混入

1.新建mixin.js文件

mixin.png

//导出对象
export const hunhe = {
    data() {
        return {
            name: '祝志鹏',
            age: 21
        }
    },
    methods: {
        say() {
            console.log(this.name);
        }
    }
}
​
export const hunhe1 = {
    data() {
        return {
            hobby: '蛇',
            sex: "女"
        }
    },
    methods: {
        speak() {
            console.log(this.sex);
        }
    }
}

2.在入口文件引入mixin.js mixin.png 3.每个组件就可以使用了

  • 局部混入

1.新建mixin.js文件

mixin1.png

//导出对象
export const hunhe = {
    data() {
        return {
            name: '祝志鹏',
            age: 21
        }
    },
    methods: {
        say() {
            console.log(this.name);
        }
    }
}
​
export const hunhe1 = {
    data() {
        return {
            hobby: '蛇',
            sex: "女"
        }
    },
    methods: {
        speak() {
            console.log(this.sex);
        }
    }
}

2.在组件文件引入mixin.js

mixin2.png 3.当前组件就可以使用了

  • 多个混入

全局混入的多个混入

mixin3.png

全局混入的多个混入

mixin4.png

vm与vc的联系

vm  vc.png

插槽

<slot> 元素作为承载分发内容的出口。父组件向子组件插入想要的内容(标签,组件,文本)

  • 子组件

image.png

  • 父组件

image.png

疯装组件

1.自定义属性传数据渲染

2.插槽使用控制结构

3.逻辑多样