写在前面
相信进来的小伙伴都对 vue 有一定的了解或者使用, 毕竟现在前端最火的框架之一, vue 是最好学的和入门相对简单, 毕竟是中文吧, 亲切感倍增, 鄙人呢, 现在的工作用的主要框架也是 vue, 平时喜欢追根溯源, 最近身边很多小伙伴去面试或者做面试官, 反馈的某某大佬, 写代码棒棒的, 但在原理和使用场景方面不够透彻, 所以在这里就总结一些大家平时不留意的点, 从 vue 入门到源码小实现, 写来旨在和大家一起交流.
从 0 开始
什么是 vue?
vue(读音 / u:/, 类似于 vew) 是一套用于构建用户界面的渐进式框架. 特点: 易用, 灵活, 高效 渐进式框架; 逐一递增 vue+ components+vue-router+vuex+vue-cli
什么是库, 什么是框架?
库是将代码集合成一个产品库是我们调用库中的方法实现自己的功能.(比如大家熟悉的 jQuery, 就是库.) 框架则是为解决一类问题而开发的产品框架是我们在指定的位置编写好代码, 框架帮我们调用.(vue,react,ng) 总而言之, 框架是库的升级版 plus.
- //... 引入库等
- let vm = new Vue({
- el:'#app',
- //template: '<h1>hello world</h1>',
- data:{ // 存放数据
- msg:'hello',
- info:{xxx:'xxx'},
- arr:[1,2,3,4]
- }
- });
- vm.$nextTick(()=>{
- console.log(vm.$el.innerhtml);
- console.log(vm.$options);
- });
- vm.$watch('info.xxx',function(newValue,oldValue){
- console.log(newValue,oldValue);
- })
vue 实例上的方法 vm.options nextTick 等等
当然你可以在控制台上面打印
mvvm
在传统的 mvc 中除了 mode 和 vew 以外的逻辑都放在了 controller 中, 导致 controller 逻辑复杂难以维护, 在 mwm 中 vew 和 mode 没有直接的关系, 全部通过 vIewMode 进行交互
方便大家加深印象百度一张图片:
模板语法
允许开发者声明式地将 DOM 绑定至底层 vue 实例的数据. 在使用数据前需要先声明 编写三元表达式 JavaScript 表达式
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- </head>
- <body>
- <div id="app">
- <!-- 取值表达式 可以 运算 , 取值 , 做三元 -->
- {{1+1}} {{msg}} {{flag?'ok':'no'}} {{ {name:1} }} {{ 'msg' + 'hello'}}
- </div>
- <script src="node_modules/vue/dist/vue.js">
- </script>
- <script>
- let vm = new Vue({
- el: '#app',
- data: {
- msg: 'hello',
- flag: true
- }
- });
- </script>
- </body>
- </HTML>
划重点 -△观察数据变化
vue 数据劫持, 必须要知道 Object.defineProperty, 以下是代码简单实现
- // 数据源
- let obj = {
- name:'jw',
- age: {
- age:18
- }
- }
- function observer(obj){
- if(typeof obj == 'object'){
- for(let key in obj){
- defineReactive(obj,key,obj[key]);
- }
- }
- }
- function defineReactive(obj,key,value){
- observer(value); // 判断 value 是不是一个对象 如果是对象 会继续监控
- Object.defineProperty(obj,key,{
- get(){
- return value
- },
- set(val){
- observer(val); // 如果设置的值是对象 需要在进行这个对象的监控
- console.log('数据更新了')
- value = val;
- }
- })
- }
- observer(obj);
- obj.age = {name:1};
Object.defienProperty 不支持数组的, 当然有童鞋就会问, 那如果是数组呢,
- // vue 把 这个数组上的所有方法 都重写了
- let arr = ['push','slice','shifit','unshift']
- arr.forEach(method=>{
- let oldPush = Array.prototype[method];
- Array.prototype[method] = function(value){
- console.log('数据更新了')
- oldPush.call(this,value);
- }
- })
- obj.age.push(5);
- obj.age.length--;
如果属性不存在 默认后增加的内容 并不会刷新视图
数组调用 push 是无效的
vue 指令 v-
在 vue 中 Directives) 是带有 v - 前缀的特殊特性, 主要的功能就是操作 DOM, 多的不说, 上代码说明
- <div id="app">
- <!-- 内部会进行缓存 以后使用的都是缓存里的结果 -->
- <div v-once>{{msg}}</div>
- <!-- v-html innerHTML XSS 攻击 不能将用户输入的内容展现出来 内容必须是可信任的 -->
- <div v-HTML="d"></div>
- <!-- v-if 如果不成里 dom 就会消失 -->
- <!-- v-if 控制的是 dom 有没有 v-show 控制的是样式 -->
- <!-- v-show 不支持 template -->
- <template v-show="flag">
- <div>hello</div>
- <div>123</div>
- </template>
- <div>312</div>
- </div>
v-for 记得写 key, 提高渲染效率, 后面说的 diff 算法的时候会详细说, key 可以用来区分元素, 尽量不要使用 index 做为 key 如果有唯一标示 尽量使用 唯一标示哦, 有点需要注意的, 就是 template 循环的时候 key 放在子元素上面, vue 2.5 以上要求 必须在循环时 使用 key 属性 .
- <template v-for="i in 3">
- <div :key="i+'_1'":a="i+'_1'">{{i}}</div>
- <div :key="`${i}_2`" :a="`${i}_2`" a="{{i}}">{{i}}</div>
- </template>
v-model 实现一个输入框双向绑定只需要
<input type="text" v-model="msg">
其实 v-model 是 @input + :value 的一个语法糖
<input type="text" :value="msg" @input="e=>msg=e.target.value">
计算属性 computed
小面试题:
computed 和 method 的区别
computed 有缓存, method 没有
computed 和 watch 区别
watch 可以支持异步
watch 可以实现一些简单的功能 先去想能不能用计算属性 computed 实现
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- </head>
- <body>
- <div id="app">
- {{ fullName }} {{msg}}
- </div>
- <script src="./node_modules/vue/dist/vue.js">
- </script>
- <script>
- let vm = new Vue({
- el: '#app',
- data: {
- firstName: '大',
- lastName: '飞',
- msg: 'hello',
- fullName: ''
- },
- // mounted(){ // 顺便说下, 在不同的阶段会被调用 是钩子函数
- // this.getFullName();
- // },
- methods: {
- getFullName() {
- this.fullName = this.firstName + this.lastName
- }
- },
- watch: { // vm.$watch('firstname',()=>{})
- firstName: {
- handler(newValue) {
- setTimeout(() = >{
- this.getFullName();
- },
- 1000)
- },
- immediate: true // deep:true
- },
- lastName() {
- this.getFullName();
- }
- },
- computed: { // Object.defineProperty 来实现
- fullName() { // get 方法, 有缓存 如果值没有更改会从缓存中取值
- return this.firstName + this.lastName
- }
- },
- // methods:{
- // getFullName(){
- // console.log('哈哈')
- // return this.firstName + this.lastName
- // }
- // }
- })
- </script>
- </body>
- </HTML>
computed 用法深入一点点, 相信大家平时都会有做多选框, 大家的方法估计是都是用 methods 来实现, 可以尝试用 computed, 代码更少更优雅.
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- </head>
- <body>
- <div id="app">
- 全选
- <input type="checkbox" v-model="checkAll">
- <input type="checkbox" v-for="(item,key) in checks" v-model="item.value"
- :key="key">
- </div>
- <script src="./node_modules/vue/dist/vue.js">
- </script>
- <script>
- let vm = new Vue({
- el: '#app',
- data: {
- checks: [{
- value: true
- },
- {
- value: false
- },
- {
- value: true
- }],
- },
- computed: {
- checkAll: {
- get() {
- return this.checks.every(check = >check.value)
- },
- set(value) { // 双向绑定数据
- this.checks.forEach(check = >check.value = value);
- }
- }
- }
- })
- </script>
- </body>
- </HTML>
今晚先写到这里, 有空再继续更新自定义指令, 生命周期, router,vuex, 基本的坑点讲完后, 我们再看看她们简单实现的小原理. 感谢你, 能够看到这里. See you !
来源: https://juejin.im/post/5c74aae3518825787e69ff0a