vue基础(1):深入理解vue(基础)

文章目录

  • 一、Vue起步
    • 1. MVVM模式是什么
    • 2. 创建一个vue实例
    • 3. v-model v-on v-for
    • 4.组件基础
      • 4.1 局部组件
    • 4.2 全局组件
    • 4.3 父组件通过 `props` 和`v-bind`向子组件传递数据(父组件 → 子组件)
    • 4.4 子组件通过事件`this.$emit()`向父级组件发送事件(数据)(子组件 → 父组件)
  • 二、深入理解vue(基础)
    • 1. Vue实例
      • `Vue`实例上的属性和方法。
    • 2. Vue实例生命周期函数
    • 3. 模板语法
    • 4. 计算属性、方法和侦听器
      • 4.1 computed 计算属性
        • 4.1.1 computed 计算属性的setter和getter
      • 4.2 methods
      • 4.3 watch(监听属性)
    • 5. vue中的class和style的样式绑定
      • 5.1 class的对象绑定
      • 5.2 class的数组绑定
      • 5.3 style的对象绑定
      • 5.4 style的数组绑定
    • 6. vue中的条件渲染
      • 6.1 v-if 和 v-else
        • v-if
        • v-else
      • 6.2 v-show
      • 6.3 v-if和v-else在切换时,input框被复用内容没有被清空的bug
    • 7.vue中的列表渲染
      • 7.1 渲染数组
      • 7.2 渲染对象
      • 7.3 key
      • 7.4 改变数组和对象的内容,保证页面实时响应
      • 7.5 使用set方法改变数组和对象中的值,保证页面实时响应
      • 7.6 ``来包裹多个标签

一、Vue起步

1. MVVM模式是什么

传统的mvp模式

  • m层指的是数据层(model)
  • v层指的是视图层(view)
  • p层指的是控制器

该编码方式一般用于普通操作dom方式,改变视图后通过控制器,进行大量dom操作,调用数据或者操作视图,核心是在p层

mvvm模式

  • m层指的是数据层(model)
  • v层指的是视图层(view)
  • vm层指的是vue自带的层(viewmodel)

也就是说使用vue进行前端开发,我们只需要关心view层Model层就行,操作dom就由vue来实现。在vm层中的实现主要使用了es5的object.definproperties和虚拟dom的机制。
vue基础(1):深入理解vue(基础)_第1张图片




2. 创建一个vue实例

  • new一个Vue实例(也就是根实例)
  • 初始化Vue实例的配置项参数:
    • el (Vue实例接管dom元素,也就是说使用vue,就无需使用js的dom操作了),
    • data(数据),
  • {{}}输出数据,只有被Vue实例接管的dom节点才能输出。
  • $data 是 data的别名
	
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>第一个vue实例title>
		
		<script type="text/javascript" src="./vue.js">script>
	head>
	<body>
		<div id="app">{{content}}div>
		<script type="text/javascript">
			var app = new Vue({
				el: '#app',			实例接管的dom
				data: {
					content: 'hello world!',
				}
			});
			
			2秒后,修改显示内容
			setTimeout(()=>{app.$data.content='hello poorpenguin!'},2000);
		script>
	body>
	html>



3. v-model v-on v-for

  • v-model 对表单和变量进行双向绑定(哪一方的值改变,另一方也随之改变)v-model="变量名"
  • v-on (v-on:简写@)监听dom事件 v-on:事件="方法名"或者@事件="方法名"
  • v-for 列表渲染v-for="item in items"或者v-for="(item, index) in items(index为数组项下标)"

<html lang="en">
<head>
	<meta charset="UTF-8">
	<script type="text/javascript" src="./vue.js">script>
head>
<body>
	<div id="todolist">
		<input type="text" v-model="inputValue"/>
		<button @click="add">添加button>
		<ul>
			<li v-for="item in list">{{item}}li>
		ul>
	div>
	<script type="text/javascript">
		var todolist = new Vue({
			el: '#todolist',
			data: {
				list: [],
				inputValue: '',
			},
			methods: {
				add(){
					this.list.push(this.inputValue);
					this.inputValue = '';
				},
			}
		});
	script>
body>
html>



4.组件基础

通过Vue实例接管的dom元素,我们就可以看成是一个组件。相对于全局注册局部注册的组件来说,Vue实例就是父组件。

  • 每一个组件就是一个vue实例。

4.1 局部组件

局部组件是在局部注册的。
使用一个普通的js对象定义组件,再在Vue实例中注册components:{}

	<div id="todolist">
		<input type="text" v-model="inputValue"/>
		<button @click="add">添加button>
		<ul>
			<to-do-list :content="item" :index="index" v-for="(item, index) in list">to-do-list>
		ul>
	div>
	<script type="text/javascript">
		var ToDoList = {
			props: ['content','index'],
			template: '
  • {{index}}.{{content}}
  • '
    , }; var todolist = new Vue({ el: '#todolist', components: { ToDoList: ToDoList, //可以ES6简写 ToDoList, //或者'to-do-list': ToDoList, }, data: { list: [], inputValue: '', }, methods: { add(){ this.list.push(this.inputValue); this.inputValue = ''; }, } });
    script>

    4.2 全局组件

    通过 Vue.component 来创建组件,就是全局注册的组件。

    	<div id="todolist">
    		<input type="text" v-model="inputValue"/>
    		<button @click="add">添加button>
    		<ul>
    			<to-do-list :content="item" :index="index" v-for="(item, index) in list">to-do-list>
    		ul>
    	div>
    	<script type="text/javascript">
    		Vue.component('to-do-list',{
    			props: ['content','index'],
    			template: '
  • {{index}}.{{content}}
  • '
    , }); var todolist = new Vue({ el: '#todolist', data: { list: [], inputValue: '', }, methods: { add(){ this.list.push(this.inputValue); this.inputValue = ''; }, } });
    script>



    4.3 父组件通过 propsv-bind向子组件传递数据(父组件 → 子组件)

    • v-bind 简写:

    在子组件中,通过props:['变量名1','变量名2'...]定义接收数据的变量。

    	Vue.component('to-do-list',{
    		props: ['content','index'],
    		template: '
  • {{index}}.{{content}}
  • '
    , });

    在父组件中,通过v-bind:子组件变量 = "变量"向子组件中定义的变量传递数据。

    <to-do-list :content="item" :index="index" v-for="(item, index) in list">to-do-list>
    

    4.4 子组件通过事件this.$emit()向父级组件发送事件(数据)(子组件 → 父组件)

    子组件通过 $emit('子事件1', 参数) 方法向外派发事件,传递参数(可选)。

    	Vue.component('to-do-list',{
    		props: ['content','index'],
    		template: '
  • {{index}}.{{content}}
  • '
    , methods: { deleteItem: function(){ this.$emit('delete',this.index); } } });

    父组件通过v-on:子事件1= "方法"来监听子组件的事件,和接收参数。

    	<div id="todolist">
    		<input type="text" v-model="inputValue"/>
    		<button @click="add">添加button>
    		<ul>
    			<to-do-list 
    				:content="item" 
    				:index="index" 
    				v-for="(item, index) in list" 
    				@delete="deleteSonItem"
    			>to-do-list>
    		ul>
    	div>
    	<script type="text/javascript">
    		Vue.component('to-do-list',{
    			....
    		});
    
    		var todolist = new Vue({
    			el: '#todolist',
    			data: {
    				list: [],
    				inputValue: '',
    			},
    			methods: {
    				add(){
    					this.list.push(this.inputValue);
    					this.inputValue = '';
    				},
    				deleteSonItem(index){	//接收子组件的参数
    					this.list.splice(index,1);
    				}
    			}
    		});
    	script>
    

    二、深入理解vue(基础)

    1. Vue实例

    • 通过new Vue()得到的Vue实例,叫做根实例
    • 通过全局注册局部注册的组件都是一个个Vue实例。
    • 一个Vue的项目由多个组件或者说是多个实例组成的。

    Vue实例上的属性和方法。

    	var vm = new Vue({
    		el: '#todolist',
    		data: {
    			list: [],
    			inputValue: '',
    		},
    		methods: {
    			add(){
    				this.list.push(this.inputValue);
    				this.inputValue = '';
    			},
    			deleteSonItem(index){
    				this.list.splice(index,1);
    			}
    		}
    	});
    	console.log(vm);	
    

    vue基础(1):深入理解vue(基础)_第2张图片

    常用的实例属性和方法

    1. vm.$data:vue实例中定义的属性
    2. vm.$el:vue实例接管的dom元素
    3. vm.$destory():销毁vue实例



    2. Vue实例生命周期函数

    生命周期函数: 实例化过程的某一时刻自动执行的函数

    首次加载页面时

    • beforeCreate:在实例部分(事件/生命周期)初始化完成之后调用。
    • created:在完成外部的注入/双向的绑定等的初始化之后调用。
    • beforeMount:在页面渲染之前执行。
    • mounted:dom 元素在挂载到页面之后执行。

    首次加载页面时,不会走这两个钩子,只有当数据发生改变时才会执行:

    • beforeUpdate:数据改变,还没重新渲染之前执行。
    • updated:渲染数据完成之后执行。

    执行销毁需要调用:vm.$destroy()

    • beforeDestroy:实例销毁之前执行。
    • destroyed:实例销毁之后执行。

    生命周期函数不需要写在methods对象中,直接放在Vue实例中即可。

    	var vm =new Vue({
    		el: '#app';
    		beforeCreate: function(){},
    		created: function(){},
    		beforeMount: function(){},
    		mounted: function(){},
    		beforeUpdate: function(){},
    		updated: function(){},
    		beforeDestroy: function(){},
    		destroyed: function(){},
    	});
    

    3. 模板语法

    • 插值表达式{{}}
    • v-text:直接显示内容,和插值类似
    • v-html:以将传入的HTML标签转义成HTML语言(容易导致 XSS 攻击,不要对用户提供的内容使用插值)
    • 所有v-指令和插值表达式中都是js表达式
    	<div id="app">
    		<div>{{str}}div>
    		<div v-text="str">div>
    		<div v-html="str">div>
    		<hr>
    		<div>{{str + ' poorpenguin'}}div>
    		<div v-text="str + 'poorpenguin'">div>
    		<div v-html="str + 'poorpenguin'">div>
    		<hr>
    		<div>{{num+1}}div>
    		<div v-text="num + 1">div>
    	div>
    	<script type="text/javascript">
    		var app = new Vue({
    			el: '#app',
    			data: {
    				str: '

    hello

    '
    , num: 1, }, });
    script>

    vue基础(1):深入理解vue(基础)_第3张图片


    4. 计算属性、方法和侦听器

    当data中的任何值发生改变的时候,页面会重新渲染。

    • computed(计算属性)性能相对较高,计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。
    • methods(方法属性),没有缓存机制,当数据发生变化,重新渲染页面时,会重新执行页面调用的方法。(性能低)
    • watch(监听属性),一个对象,键是需要观察的表达式,值是对应回调函数,跟computed 类似,有缓存机制,但代码冗余。

    所以一个需求如用computed、methods、watch都可以实现的话,推荐用computed、既简洁性能又高

    4.1 computed 计算属性

    计算属性的会缓存上一次计算的结果,只有当计算结果依赖的属性没有发生改变的时候,是不会重新计算的。

    	<div id="app">
    		<div>{{fullname}}div>
    		<div>{{age}}div>
    	div>
    
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				word: 'hello',
    				name: 'poorpenguin',
    				age: 25,
    			},
    			computed: {
    				fullname: function(){
    					console.log('重新计算了一次!');
    					return this.word+' '+this.name;
    				}
    			}
    		});
    	script>
    

    vue基础(1):深入理解vue(基础)_第4张图片

    4.1.1 computed 计算属性的setter和getter

    计算属性默认是只有getter, 也就是可以直接计算属性:function(){...}这样写

    	computed: {
    		fullname: function(){
    			console.log('重新计算了一次!');
    			return this.word+' '+this.name;
    		}
    	}
    

    如果要使用setter,计算属性就要是一个对象。

    	<div id="app">
    		<div>{{fullname}}div>
    		<div>{{age}}div>
    	div>
    
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				word: 'hello',
    				name: 'poorpenguin',
    				age: 25,
    			},
    			computed: {
    				fullname: {
    					get: function(){
    						return this.word+''+this.name;
    					},
    					set: function(value){		
    						value可以获得通过vm.fullname设置新的计算属性,就可以手动改变所依赖的变量。
    						var arr = value.split(' ');
    						this.word = arr[0];
    						this.name = arr[1];
    					}
    				}
    			}
    		});
    	script>
    

    4.2 methods

    当数据发生变化,重新渲染页面时,会重新执行页面调用的方法。

    	<div id="app">
    		<div>{{fullname()}}div>
    		<div>{{age}}div>
    	div>
    
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				word: 'hello',
    				name: 'poorpenguin',
    				age: 25,
    			},
    			methods: {
    				fullname: function(){
    					console.log('重新计算了一次!');
    					return this.word+' '+this.name;
    				}
    			}
    		});
    	script>
    

    vue基础(1):深入理解vue(基础)_第5张图片


    4.3 watch(监听属性)

    可以监听数据的变化,并执行相应的回调函数。

    	<div id="app">
    		<div>{{fullname}}div>
    		<div>{{age}}div>
    	div>
    
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				word: 'hello',
    				name: 'poorpenguin',
    				fullname: 'hello poorpenguin',
    				age: 25,
    			},
    			watch: {
    				word: function(){
    					console.log('执行了一次!');
    					this.fullname = this.word+' '+this.name;
    				},
    				name: function(){
    					console.log('执行了一次!');
    					this.fullname = this.word+' '+this.name;	
    				}
    			}
    		});
    	script>
    

    vue基础(1):深入理解vue(基础)_第6张图片




    5. vue中的class和style的样式绑定

    使用v-bind:class="js表达式":class="js表达式"绑定样式,可以和元素原本的class属性共存

    vue中给dom元素绑定class方式

    1. class的对象绑定
    	<div :class="{activated: isActivated}">
    
    1. class的数组绑定
    	<div :class="[activated1,activated2]">
    

    vue中给dom元素绑定style内联样式

    1. style的对象绑定
    	<div :style="styleObj">
    
    1. style的数组绑定
    	写法一:
    	<div :style="[styleObj1, {fontSize: '14px'}]">
    	写法二:
    	<div :style="[styleObj1, styleObj12]">
    

    5.1 class的对象绑定

    v-命令后面是一个js表达式,所以可以直接给class绑定一个对象。

    	<div id="app">
    		<h1 v-bind:class="{activated: isActivated }" v-on:click="clickH1">Hello poorpenguinh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				isActivated: false,
    			},
    			methods: {
    				clickH1: function(){
    					this.isActivated = !this.isActivated;
    				},
    			}
    		});
    	script>
    

    5.2 class的数组绑定

    数组中每一项都是一个对象,剩下的就可以自由发挥了。

    	<style>
    		.activated-color{
    			color: red;
    		}
    		.activated-size{
    			font-size: 14px;
    		}
    	style>
    	<div id="app">
    		<h1 v-bind:class="[activated1,activated2]" v-on:click="clickH1">Hello poorpenguinh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				activated1: '',
    				activated2: '',
    			},
    			methods: {
    				clickH1: function(){
    					this.activated1 = this.activated1 === ''? 'activated-color':'';
    					this.activated2 = this.activated2 === ''? 'activated-size':'';
    				},
    			}
    		});
    	script>
    

    5.3 style的对象绑定

    直接绑定一个对象。

    	<div id="app">
    		<h1 v-bind:style="styleObj" v-on:click="clickH1">Hello poorpenguinh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				styleObj: {
    					color: '',
    					fontSize: '',
    				}
    			},
    			methods: {
    				clickH1: function(){
    					this.styleObj.color = this.styleObj.color === ''? 'red':'';
    					this.styleObj.fontSize = this.styleObj.fontSize === ''? '14px':'';
    				},
    			}
    		});
    	script>
    

    5.4 style的数组绑定

    数组中每一项都是一个对象。

    	<div id="app">
    		<h1 v-bind:style="[styleObj1, styleObj2]" v-on:click="clickH1">Hello poorpenguinh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				styleObj1: {
    					color: '',
    				},
    				styleObj2: {
    					fontSize: '',
    				}
    			},
    			methods: {
    				clickH1: function(){
    					this.styleObj1.color = this.styleObj1.color === ''? 'red':'';
    					this.styleObj2.fontSize = this.styleObj2.fontSize === ''? '14px':'';
    				},
    			}
    		});
    	script>
    



    6. vue中的条件渲染

    • v-if:根据表达式的值的真假条件渲染元素,在切换时元素及它的数据绑定 / 组件被销毁并重建,v-if/v-else-if/v-else 必须连在一起使用。
    • v-show:根据表达式值的真假,决定元素在页面上是否隐藏,通过切换元素的 display CSS 属性实现。

    6.1 v-if 和 v-else

    v-if

    v-if的值为false,dom元素是不会挂载到页面上的。

    	<div id="app">
    		<h1 v-if="show">Hello poorpenguinh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				show: false,
    			}
    		});
    	script>
    

    在这里插入图片描述
    只有当v-if的值为true时才会挂载到页面上。
    在这里插入图片描述
    在这里插入图片描述


    v-else

    v-if/v-else-if/v-else 必须连在一起使用,中间不能被任何标签分隔,不然会报错。

    	<div id="app">
    		<h1 v-if="show === 'a'">This is Ah1>
    		<h1 v-else-if="show === 'b'">This is bh1>
    		<h1 v-else>This is othersh1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				show: 'a',
    			}
    		});
    	script>
    

    6.2 v-show

    v-show的值为false,是dom元素在dom树中还是存在的。

    	<div id="app">
    		<h1 v-show="show">This is Ah1>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				show: false,
    			}
    		});
    	script>
    

    在这里插入图片描述


    6.3 v-if和v-else在切换时,input框被复用内容没有被清空的bug

    	<div id="app">
    		<div v-if="show">用户名:<input type="text">div>
    		<div v-else>邮箱:<input type="text">div>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				show: true,
    			}
    		});
    	script>
    

    在输入框输入内容。
    在这里插入图片描述
    设置v-show的值为false
    在这里插入图片描述

    Vue在数据更新的时候,会尝试复用已经存在的 dom,使用 key 属性来设置 dom 的唯一性,这样可以避免复用了。

    	<div id="app">
    		<div v-if="show">用户名:<input type="text" key="username">div>
    		<div v-else>邮箱:<input type="text" key="email">div>
    	div>
    



    7.vue中的列表渲染

    渲染列表我们可以使用

    也可以使用

    7.1 渲染数组

    item为数组项,index为下标

    	<div id="app">
    		<div v-for="(item,index) of list">{{index+1}}--{{item}}div>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				list: ['poorpenguin','阿西吧','苟','铁骨铮铮王'],
    			}
    		});
    	script>
    

    7.2 渲染对象

    	<div id="app">
    		<div v-for="(item,key,index) of userInfo">{{index+1}}. {{key}} : {{item}}div>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				userInfo: {
    					name: 'poorpenguin',
    					age: 25,
    					sex: 'male',
    					salary: 'secret',
    				},
    			}
    		});
    	script>
    

    vue基础(1):深入理解vue(基础)_第7张图片


    7.3 key

    在正常项目开发的时候,后端返回给前端的数据都会带有数据表的主键id,建议将id作为循环项的key值。

    	<div id="app">
    		<div v-for="(item,index) of users"
    			 :key="item.id">{{index+1}}——{{item.name}}——{{item.remark}}div>
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				users: [
    					{
    						id: '123',
    						name: '王境泽',
    						age: '20',
    						remark: '哎,真香!'
    					},
    					{
    						id: '124',
    						name: '鲁迅',
    						age: '90',
    						remark: '横眉冷对千夫指,俯首甘为孺子牛!'
    					},
    										{
    						id: '125',
    						name: '张学友',
    						age: '50',
    						remark: '食屎啦你!'
    					},
    					{
    						id: '126',
    						name: '王建森',
    						age: '52',
    						remark: '先赚他一个亿!'
    					},
    
    				]
    			}
    		});
    	script>
    

    7.4 改变数组和对象的内容,保证页面实时响应

    1. 在 vue 里不能通过数组的下标值来改变数组,因为这个做法是没有响应式效果的,只能通过数组本身的7个变异方法
      • push 在数组最后添加一个元素
      • pop 删除最后一个
      • shift删除数组第一个元素
      • unshift往数组中最前添加一个元素
      • splice 截取或替换操作 使用方法splice(下标,数量,内容)
      • sort 排序
      • reverse 数组取反
    2. 通过改变数组本身的引用实现(对象也是如此)。
      vue基础(1):深入理解vue(基础)_第8张图片

    7.5 使用set方法改变数组和对象中的值,保证页面实时响应

    set有两种使用方式

    • Vue.set() 通过全局的方式使用
    • vm.$set() 通过实例的方式使用

    两种使用的方式一样。

    set()改变数组

    	Vue.set(vm.数组, 下标, 内容);
    	vm.$set(vm.数组, 下标, 内容);
    
    	<div id="app">
    		<template v-for="(item,index) of users">
    			<h1>{{item.name}}h1>
    			<div>{{item.remark}}div>
    			<hr>
    		template> 
    	div>
    	<script type="text/javascript">
    		var vm = new Vue({
    			el: '#app',
    			data: {
    				users: [
    					{
    						id: '123',
    						name: '王境泽',
    						age: '20',
    						remark: '哎,真香!'
    					},
    					{
    						id: '124',
    						name: '鲁迅',
    						age: '90',
    						remark: '横眉冷对千夫指,俯首甘为孺子牛!'
    					},
    										{
    						id: '125',
    						name: '张学友',
    						age: '50',
    						remark: '食屎啦你!'
    					},
    					{
    						id: '126',
    						name: '王建森',
    						age: '52',
    						remark: '先赚他一个亿!'
    					},
    				]
    			}
    		});
    	script>
    

    vue基础(1):深入理解vue(基础)_第9张图片

    set()改变对象

    	Vue.set(vm.对象, 键名, 键值);
    	vm.$set(vm.对象, 键名, 键值);
    

    7.6