Vue学习总结(更新中)

92 阅读8分钟

前端小白简单总结,参考黑马珠峰等课程以及其他内容整合,还望各位大佬多多指教~

Vue基础

零、Vue前置知识:es6部分内容

参见ES6部分内容(Vue前置内容)

一、Vue初识

  • vue数据驱动(主要操作的是数据)
  • js、jQuery都是操作dom,导致页面重复渲染

框架和库

  • 框架:vue 拥有完整的解决方案,我们写好人家调用我
  • 库:jquery underscore zepto animate.css 我们调用他

1、Vue简介

因为Object.defineProperty(es5)的没有替代方案,所以不支持ie8以下版本

Vue.js(读音 /vju:/,类似于view) 是一套构建用户界面的渐进式(渐近增强)框架,它只关注视图层。

  • 声明式渲染(无需关心如何实现)
  • 组件系统
  • 客户端路由(vue-router)
  • 集中式状态管理(vuex)
  • 项目构建(vue-cli)
    在这里插入图片描述

2、优点:

  • 易用:熟悉HTML、CSS、JavaScript知识后,可快速上手Vue
  • 灵活:在一个库和一套完整框架之间自如伸缩
  • 高效:20kB运行大小,超快虚拟DOM

3、主要开发思想

  • 组件化开发:
    把页面拆分成多个组件,ui页面映射为组件树,每个组件依赖的模板(html) css、js等资源放在一起开发、维护和测试
  • 响应的数据变化(数据驱动视图):
    当数据发生改变时 -> 视图随之发生改变

4、Vue基本使用

    1) Vue使用的基本步骤
        1> 需要提供标签用于填充数据
        2> 引入vue.js库文件
        3> 可以使用vue的语法做功能了
        4> 把vue提供的数据填充到标签里面
    2) Hello World实例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>

<body>
    <div id="app">
        <div>{{msg}}</div>
        <div>{{1+1}}</div>
        <div>{{msg+'-----'+123}}</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
    // 引入vue会给你一个Vue构造函数
        var vm = new Vue({ // vm = viewModel
            el: '#app', // 告诉vue能管理哪个部分,querySelector
            data: { // data中的数据会被vm所代理
                msg: 'Hello World' // 可以通过vm.msg取到对应的内容
            }
        }) // Object.defineProperty
    </script>
</body>

</html>

1、实例参数分析:

  • el:元素挂载位置(值可以是CSS选择器或者DOM元素)

  • data:模型数据(值是一个对象)

2、差值表达式用法:

-#### 将数据填充到HTML标签中
-#### 差值表达式支持基本的计算操作

5、Vue代码运行原理分析

概述编译过程的概念(Vue语法—>原生语法)

在这里插入图片描述

5、Vue环境搭建(Vue-cli脚手架)

参见:Vue环境搭建(Vue-cli脚手架)

二、Vue的模板语法

1、前端渲染

1) 定义:把数据填充到HTML标签中

在这里插入图片描述

2) 前端渲染方式

  • 原生js拼接字符串
  • 使用前端模板引擎
  • 使用vue特有的模板语法

3)模板语法概览:

  • 差值表达式
  • 指令
  • 事件绑定
  • 属性绑定
  • 样式绑定
  • 分支循环结构

2、差值表达式(moustache 小胡子语法)

  • 将数据填充到HTML标签中

  • 差值表达式支持表达式、赋值、三元运算等

	<div>{{ msg }}</div>
	<div>{{ 1+1 }}</div>
	<div>{{ msg+'-----'+123 }}</div>

3、指令(dom元素的行间属性)

1)定义:

  • 本质就是自定义属性
  • 指令的格式:Vue中都是以v-开头的

vue的指令directive只是dom上的行间属性,vue给这类属性赋予
一定的意义,来实现特殊的功能,所有指令都以v-开头,value属
性默认情况下,vue会忽略掉 selected checked都没有意义

2)v-cloak指令

  • v-cloak:防止页面加载时出现闪烁问题;
“闪动”产生原因:Vue解析差值表达式是先将差值表达式显示在页面中,然后迅速替换为对应的内容;
原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终的结果;

3)数据绑定指令

  • v-text:填充纯文本(单向绑定,数据对象上的值改变,插值会发生变化;但是当插值发生变化并不会影响数据对象的值)。
       特点:相比差值表达式更加简洁,没有“闪动”问题
  • v-html: 填充HTMl片段
           1、存在安全问题
           2、本网站内部数据可以使用,来自第三方的数据不可以用
           3、重复渲染,影响性能
  • v-pre:填充原始信息
           1、显示原始信息,跳过编译过程

4)数据响应式

1> 如何理解数据响应式
        1、html5中的响应式:屏幕尺寸变化导致样式的变化
        2、数据的响应式:数据的变化导致页面内容的变化
2> 数据绑定:将数据填充到标签中
3> v-once:只编译一次,
        1、显示内容之后不再具有响应式功能
        2、应用场景:如果显示的信息后续不需要再修改,这样可以提高性能

5)自定义指令:directive:用来操作dom

	<button v-color="flag">变色</button>
	<div v-drag></div>
	<script>
		let vm = new Vue({
			directives: {
				color(el, bindings){ // el指代的是当前操作的dom,当前是指button按钮
					el.style.background = bindings.value
				},
				drag(el){
					el.onmousedown = function(e){
						var disx = e.pageX - el.offsetLeft;
						var disy = e.pageY - el.offsetTop;
						document.onmousemove = function(e){
							el.style.left = e.pageX - disx + 'px';
							el.style.top = e.pageY - disy + 'px';	
						}
						document.onmouseup = function(){
							document.onmousemove = document.onmouse = null
						}
						e.preventDefault();
					}	
				}	
			}
		})
	</script>

4、双向数据绑定

1)数据变化会导致显示发生变化

2)修改页面内容导致数据发生变化

在这里插入图片描述

vue会循环data中的数据(数据劫持),依次的增加getter和setter
使用变量时,先要初始化,否则新加的属性不会导致页面刷新
给对象添加响应式的数据变化有三种方法:
1> 变量初始化
2> 使用setter添加属性:vm.$set(vm.a, ‘school’, 1) // 此方法可以给对象添加响应式的数据变化
3> 替换原对象:vm.a = {school: ‘1’}

要想改变数组的某一项(重点)

data: {
arr: [1, 2, 3, 4, 5]
}
错误:
vm.arr[0] = 100; // 去改变数组中的某一项是监控不到的
vm.arr.length -=2; // 也不能使用改变数组长度的方法

只能使用变异方法:
pop push shift unshift sort reverse splice
或filter map

vm.arr = vm.arr.map(item=>item*=3); 
  • v-model(底层是事件绑定)
// v-model会将msg的值赋予输入框,输入框的值改变了会影响数据
<input type="text" v-model="uname" />

数据双向绑定的简单原理实现:(Object.defineProperty)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="text" id="input">
<script src="node_modules/vue/dist/vue.js"></script>
<script>
  let obj = {};
  // Object.defineProperty(obj, 'name', {
  //   configurable: false, // 是否可配置(删除)
  //   writable: false, // 是否可重新赋值
  //   enumerable: false, // 是否可枚举
  //   value: 1
  // })
  // delete obj.name
  // obj.name = 1000
  // for(key in obj){
  //   console.log(key)
  // }
  Object.defineProperty(obj, 'name', {
    get(){ // 取obj的name属性会触发
      return temp['name']
    },
    set(val){// 给obj赋值会触发set方法
      console.log(val);
      // obj.name = val; // 会反复调用set,造成死循环
      temp['name'] = val; // 改变temp的结果
      input.value = val; // 将值赋予输入框
    }
  });
  input.value = obj.name; // 页面一加载时,会调用get方法
  input.addEventListener('input', function () { // 等待输入框的变化
      obj.name = this.value; // 当值变化时会调用set方法
  })
</script>
</body>
</html>
	

多用于表单元素,忽略value, checked, selected,将数据绑定到视图上,视图修改后会影响数据的变化

如果是复选框,只有一个复选框的时候,会把此值转化为boolean类型,如果true则代表选中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{ title }}</h1>
        爱好:   <input type="checkbox" v-model="a" />跑步
    {{ a }}
    </div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            title: 'checkbox demo',
            a: ''
        }
    })

</script>
</body>
</html>

结果如图:
在这里插入图片描述

如果是多个checkbox,要增加value属性并且数据类型是数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{ title }}</h1>
        爱好:   <input type="checkbox" v-model="a" value="跑步"/>跑步
                <input type="checkbox" v-model="a" value="骑行"/>骑行
                <input type="checkbox" v-model="a" value="游泳"/>游泳
    {{ a }}
    </div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            title: 'checkbox demo',
            a: []
        }
    })

</script>
</body>
</html>

结果如图:
在这里插入图片描述

下拉框select也是同理:
原生js实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>原生js实现下拉框</title>
</head>
<body>
<select id="select">
    <option value="跑步">跑步</option>
    <option value="骑行">骑行</option>
    <option value="游泳">游泳</option>
</select>
</body>
<script>
    let oSelect = document.getElementById('select');
    oSelect.onchange = function (){
        console.log(this.value)
    }
</script>
</html>

vue方式实现:
如果select是多选框,数据类型要是数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{ title }}</h1>
        <select>
            <option value="" disabled multiple>请选择</option>
            <option value="跑步">跑步</option>
            <option value="骑行">骑行</option>
            <option value="游泳">游泳</option>
        </select>
    </div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            title: 'select demo',
            a: []
        }
    })

</script>
</body>
</html>

单选框radio同理

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
   <div id="app">
       <h1>{{ title }}</h1>
       <input type="radio" v-model="gender" value="男" /><input type="radio" v-model="gender" value="女" />女 {{ gender }}
   </div>
<script>
   var vm = new Vue({
       el: '#app',
       data: {
           title: 'select demo',
           gender: '男'
       }
   })

</script>
</body>
</html>

MVC设计思想(backbone、或者结合后端)单向

  • M:model数据
  • V: view视图
  • C: controller 控制器在这里插入图片描述

MVVM设计思想(angular, vue)双向

在这里插入图片描述

  • M(model)
  • V(view)
  • VM(View-Model)

5、事件绑定

原生js事件绑定:

<div onclick="fn()" id="btn">点击</div>
<script>
	function fn() {
		alert(1);
	}
	console.log(btn.onclick); // onclick(event){fn}
</script>

v-on: 在dom节点上绑定一个事件,简写为@

1)事件绑定方式

1> 直接绑定函数名称
<button @click="hello">hello1<button>
2> 调用函数
<button @click="hello()">hello2<button>
3> 普通参数和事件对象
如果不传递参数,则不要写括号会自动传入事件源$event,如果写括号了要手动传入$event属性
// 如果事件绑定函数调用,事件对象必须作为最后一个参数显示传递,并且名称必须是$event 
<button @click="hello("hi", $event)">hello3<button>

2)常用事件修饰符(连写会有先后顺序)

  • .stop:阻止冒泡

原生js方式:event.stopPropagation();

<a v-on:click.stop="handle">跳转</a>
  • .prevent:阻止默认行为

原生js方式:event.preventDefault();

<a v-on:click.prevent="handle">跳转</a>
  • .once:只执行一次
  • .self:

3)常用按键修饰符

  • .enter:回车键
<input v-on:keyup.enter="submit">
  • .delete:删除键
<input v-on:keyup.delete="handle">

4)自定义按键修饰符

  • 全局config.keyCodes对象
// 名是自定义的,但是对应的值必须是按键对应event
Vue.config.keyCodes.f12 = 65

6、属性绑定

1)动态处理属性

  • v-bind,可简写为:
<a v-bind:href="url">跳转</a>
<a:href="url">跳转</a>

2)v-model的底层实现原理分析(有面试问过)

用v-bind绑定一个属性msg,用v-on绑定一个事件,事件中将msg的值替换为当前input的值。

<input v-bind:value="msg" v-on:input="msg=$event.target.value">

7、样式绑定

1)class样式处理

  • 对象语法
<div v-bind:class="{ active: isActive }"></div>
  • 数组语法
<div v-bind:class="[ activeClass, errorClass ]"></div>
  • 相关语法细节:

1> 对象绑定和数组绑定可以结合使用

<div v-bind:class="[ activeClass, errorClass, {test: isTest} ]"></div>
data:{
	activeClass: 'active',
	errorClass: 'error',
	isTest: true
}

2> class绑定的值可以简化操作

<div v-bind:class="arrClasses"></div>
<div v-bind:class="objClasses"></div>
data:{
	activeClass: 'active',
	errorClass: 'error',
	arrClasses: ['active', 'error'],	
	objClasses: {
		active: true,
		error: true
	}
}

3> 默认的class会保留

<div class="base" v-bind:class="objClasses"></div>
data:{	
	objClasses: {
		active: true,
		error: true
	}
}

2)style样式处理

  • 对象语法
<div v-bind:style="{ color:activeColor, fontSize: fontSize }"></div>
data:{	
	activeColor: '#ccc',
	fontSize: 12px
}

可简化为:

<div v-bind:style="objStyles"></div>
data:{	
	objStyles:{
		activeColor: '#ccc',
		fontSize: 12px
	}	
}
  • 数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>

8、分支循环结构

1)分支结构

  • v-if
  • v-else
  • v-else-if
<div v-if="score>=90">优秀</div>
<div v-else-if="score<90&&score>=80">良好</div>
<div v-else-if="score>=70&&score>=60">一般</div>
<div v-else>比较差</div>
data:{	
	score: 80
	}	
}
  • v-show: 用于显示和隐藏dom节点
<div v-show>测试v-show</div>

2)v-if与v-show的区别(性能考虑推荐v-show)

  • v-if控制元素是否渲染到页面(操作的是dom,控制dom节点是否显示)
  • v-show控制元素是否显示(操作的是样式,已经渲染到了页面,改变display属性)
  • 如果频繁的切换dom,使用v-show,当数据一开始就确定下来使用v-if,如果if不通过内部指令不会再执行了

在这里插入图片描述
使用样例:

<template>
  <div class="hello">
    <h1 v-cloak>{{ msg }}</h1>
    <h2 v-html="xx"></h2>
    <h2 v-show="isTrue">v-show指令</h2>
    <h2 v-if="isTrue">v-if指令</h2>
    <input v-on:click="fnxx" type="button" value="显示/隐藏" />
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 模型数据方法:返回值是一个对象  
  data () {
    return {
      msg: '是日前端',
      xx: '日拱一卒',
      isTrue: false
    }
  },
  methods: {
      fnxx(){
        // methods中定义的函数,里面的this指向的是当前的vue实例
        // 简单方式
        this.isTrue = !this.isTrue;
      //   if(this.isTrue == false){
      //     this.isTrue=true;
      //   }else{
      //     this.isTrue=false;      
      // }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

结果如图:
在这里插入图片描述

3)循环结构

原生js中是用innerHtml拼字符串

v-for(解决循环问题的,更高效,会复用原有的结构)
使用:要循环谁就在谁的身上增加v-for属性
  • v-for遍历数组
<li v-for="item in list"> {{item}} </li>
<li v-for="(item, index) in list">{{ item }} + "---" + {{index}} </li>
data:{	
	item: [1, 2, 3, 4, 5, 6]
	}	
}
<li :key="index" v-for="(item, index) in list">
	<span> {{item.ename}} </span>
	<span> {{item.cname}} </span>
</li>
data:{	
	item: [{
		ename: 'apple',
		cname: '苹果'
	},{
		ename: 'orange',
		cname: '橘子'
	},{
		ename: 'pear',
		cname: '梨子'
	}]
   }	
}
  • key的作用:帮助Vue区分不同的元素,从而提高性能
<li :key="item.id" v-for="(item, index) in list">{{ item }} + "---" + {{index}} </li>
  • v-for遍历对象
  • 使用原生js遍历对象(for-in循环只适用于遍历对象)
var obj ={
	uname: 'Mickey',
	age: '6',
	gender: 'female'
}
for(var key in obj){
	console.log(key, obj[key]);
}
<div v-for="(value, key, index) in object"></div>
  • v-if和v-for结合使用
<div v-if="value==12" v-for="(value, key, index) in object"></div>

注意:methods和data中的数据会全部放到vm上,而且名字不能冲突,冲突会报错,methods中的this指向的都是vue实例。

案例:简易Todo List实现

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Todo List</title>

</head>
<body>
  <div id="app">
    <h1>{{ title }}</h1>
    <input type="text" v-model="todo" @keyup.enter="add"/>
    <ul>
      <li v-for="(item, index) in list">{{ item }} <button @click="del(index)">删除</button></li>
    </ul>
  </div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
      el: '#app',
      data:{
        title: 'Todo List',
        todo: "",
        list: []
      },
      methods: {
        add(){
            console.log(this.todo)
            this.list.push(this.todo)
            console.log(this.list)
            this.todo = ''
        },
        del(i){
          console.log(this.todo)
          this.list = this.list.filter((item, index) => index !== i)
        }
      }
    })
  </script>
</body>
</html>

结果如图:
在这里插入图片描述

三、过滤器

原数据不变的情况下,只是改变显示的效果,利用管道符|实现

<!-- 过滤器 原数据不变的情况下,只是改变显示的效果 管道符号 -->
<div>{{ product.product * productPrice | toFixed(2) }}</div>
filters: [{
	toFixed(input, param1){
		return '¥' + input.toFixed(param1); // input代表的是管道符前面的内容,param1代表的是toFixed中传递的参数
	}
}]

四、computed计算属性(不是方法)

表达式的计算逻辑可能会比较复杂,使用计算属性可以使模板内容更加简洁

两部分组成有get和set(不能只写set)一般情况下,通过js赋值影响其他人或者表单元素设置值的时候会调用set方法
computed默认调用get方法,必须要有returncomputed不支持异步

<div id="app">
全选 <input type="checkbox" v-model="checkAll"></input><br>
<input type="checkbox" v-for="product in products" v-model="product.isSelected">
<script src="node_modules/vue/dist/vue.js"></script>
<script>
	let vm = new Vue({
		el: '#app',
		// 当给全选赋值时,要影响其他人的变化,当页面刷新时,获取全选值,是根据下面的checkbox计算出来的结果给全选赋值
		computed: { // 放在computed中最后也会放在vm上,不能和methods与data相同
			checkAll: {
			    // 当products值变化时会重新计算
				get(){ // 返回什么结果,就会赋予给checkAll属性
				// get和set中,this指向实例 默认v-model会获取checkAll的值,所以会调用get方法
					return this.products.every((item=>item.isSelected);)
				},
				set(val){ // 当我们给checkbox赋值的时候
					this.products.forEach(p=>p.isSelected = val);
				}
			},
			sum(){  // 如果计算属性写成函数,默认调用的就是get方法
			// sum的结果会缓存,如果依赖的数据没有变化就不会重新执行
			return this.products.reduce((prev, next)=>{
				if(!next.isSelected) 
					return prev;
				return prev + next.productPrice * next.productCount;
			}, 0);
		}
	}
})
</script>
<div id="app">
	<input type="text" v-model="a">
	{{ msg }}
	<!-- 根据输入框中的内容,算出一个错误信息 -->
</div>
	<script src="node_modules/vue/dist/vue.js"></script>
	<script>
	let vm = new Vue({
		el: '#app',
		data: {a: '',
			   msg: ''},
		computed: { // computed默认调用get方法,必须要有return,computed不支持异步
			msg(){
				if(this.a.length < 3){
					return '少了'
				}	
				if(this.a.length > 6){
					return '多了'	
				}
				return '';
			}	
		}
	</script>

计算属性和methods的区别:计算属性是基于它们的依赖(归vue管理的数据,可以响应式变化的)属性进行缓存的,方法不存在缓存。

五、侦听器watch

只有值变化的时候才会触发,支持异步,当需要在数据变化时执行异步或开销较大的操作时一般使用,其他情况下我们更善于使用

  • 普通监控:watch默认只监控一层的数据变化

computed

<div id="app">
	<input type="text" v-model="a">
	{{ msg }}
	<!-- 根据输入框中的内容,算出一个错误信息 -->
</div>
	<script src="node_modules/vue/dist/vue.js"></script>
	<script>
	let vm = new Vue({
		el: '#app',
		data: {a: '', msg: ''},
		watch: { // 只有值变化的时候才会触发,支持异步,其他情况下我们更善于使用computed
			a(newVal, oldVal){ // watch的属性名要和观察的对象的名字一致
				if(newVal.length < 3){
					return this.msg = '太少'
				}
				if(newVal.length > 6){
					return this.msg = '太多'
				}	
				this.msg = '';
			}
		}
	})
	</script>
  • 深度监控:监控对象内部数据的变化

created(){ // 
    // 如果localStorage中有数据就用,没有就用默认的
	this.todos = JSON.parse(localStorage.getItem('data')) || this.todos;
}
watch:{
	todos: {
		handler(){ // 默认写成函数,就相当于默认写了个handler
			// localStorage默认存的是字符串
			localStorage.setItem('data', JSON.stringify(this.todos))
		}, deep: true	
	}	
}

六、路由

  • 访问不同的路径,就可以返回不同的结果
  • 多页面(spa)
  • single page application
  • hash方式(开发环境):通过hash记录跳转的路径(可以产生历史管理),不支持seo
  • history方式(生产环境): 浏览器自带的历史管理办法history(history.pushState( ))可能会导致404错误

七、Vue生命周期钩子函数以及实例上的属性和方法

参见:Vue生命周期钩子函数以及实例上的属性和方法简单总结

八、组件化开发

参见:Vue组件化开发简单总结

九、Vue组件间通信

参见:Vue组件间通信简单总结

十、axios的使用

参见:Vue中使用axios(Promise)

十一、vuex

参见:Vuex简单总结

如果大家想一起交流学习,共同进步,欢迎扫码进“是日前端交流群”,进群可以改下备注,地区_昵称,群里仅限技术交流、面试交流等,交流群的特色我还在考虑中,再次感谢大家的支持~

在这里插入图片描述