Vue基础

222 阅读5分钟

vue2014年,由国人尤雨溪开发出来。三大框架之一

学习路线

html/css/js=>es6=>vue基础+组件化开发=>vue核心插件vue-router+vuex=>社区技术文章=>研究底层源码

起步

引包

直接使用 <script>引入

直接下载vue.jsVue 会被注册为一个全局变量。

<script type = 'text/javascript' src='vue.js'></script>

npm 下载

npm i vue.js -S

cdn引入

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

初始化

const vm = new Vue({
	el:"#app",//指定绑定区域
	data:{
  	//存放数据
 		msg:'str'
	},
	methods:{
  	//存放方法
  		getVal(){
      		return 'hello';
  		}
	}
});

插值表达式

{{ }}可插任何数据,要插入变量,必须要在data中声明该属性

<body>
	<div id="app">
		<!-- 字符串 -->
		<h2>{{'hello'}}</h2>
		<!-- 数字 -->
		<h2>{{520}}</h2>
		<!-- 数组 -->
		<h2>{{ [1,2,3] }}</h2>
		<!-- 对象,注意分隔 -->
		<h2>{{ {id:1} }}</h2>
		<!-- 表达式,会自动计算 -->
		<h2>{{ 1>2 }}</h2>
		<!-- 变量 -->
		<h2>{{msg}}</h2>
		<!-- 函数 -->
		<h2>{{getVal()}}</h2>
	</div>
	<script type="text/javascript">
		const vm = new Vue({
			el:'#app',
			data:{
				msg:'hello vue'
			},
			methods:{
				getVal(){
					return 520;
				}
			}
		});
		console.log(vm);
	</script>
</body>

vue指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的作用是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

v-text

插入文本,直接渲染,与{{}}作用一样。类似于innerText

<h2 id="text" v-text="msg"></h2>

innerText表示

var text = document.getElementById('text');
text.innerText = 'hello vue';

v-html

可插入dom,类似于innerHTML

<div id="divBox" v-html="msg2"></div>

innerHTML表示

var divBox = document.getElementById('divBox');
divBox.innerHTML = '<p> hello vue1 </p>';

条件渲染

  • v-if

    • v-else-if

    • v-else

  • v-show

v-if

决定元素的显示与隐藏,值可以是表达式

<div v-if="num>0">会显示</div>
<div v-else-if="num>3">显示</div>
<div v-else="">隐藏</div>

作用类似于

var num = 5;
if(num>0){
    console.log('显示');
}
else if(num>3){
    console.log('继续显示')
}
else{
    console.log('隐藏')
}

v-show

也是决定元素是否显示,布尔值为true显示,反之。本质是修改display属性

v-if && v-show的区别(面试题)

v-if 是删除再添加元素,修改dom,v-show是改变样式,元素始终在dom结构中。两者为false时,元素在页面中均不占据位置。

建议

  • 频繁切换时,用v-show
  • 切换少,用v-if

v-bind

绑定 属性v-bind:属性名

既可以绑定自身的属性,又可以绑定自定义的属性

<a v-bind:href = 'res.url'>{{res.name}}</a>
<script type="text/javascript">
	const vm = new Vue({
		el:'#app',
		data:{
			res:{
            	name:'百度',
            	url:'http://www.baidu.com'
            }
		}
	});
</script>

简写方式

v-bind,简写为:

<a v-bind:href = 'res.url'>{{res.name}}</a>
<a :href = 'res.url'>{{res.name}}</a>

绑定类

可以动态切换

<h3 :class="{active:isActive}"></h3>
<script type="text/javascript">
	const vm = new Vue({
		el:'#app',
		data:{
			isActive:true,
	});
</script>

绑定行内 style

<h3 :style="{color:isColor,fontSize:fontSize}"></h3>
<script type="text/javascript">
	const vm = new Vue({
		el:'#app',
		data:{
		    isColor:'red',
            fontSize:'16px'
	});
</script>

v-on

绑定 事件v-on:事件类型

<body>
	<div id="app">
		<h3>{{num}}</h3>
		<button v-on:click="add">+</button>
	</div>
	<script type="text/javascript">
		const vm = new Vue({
			el: '#app',
			data: {
				num:0
			},
			methods:{
				add(){
					this.num++;
				}
			}
		});
	</script>
</body>

简写方式

v-on简写为 @ , @click

事件修饰符

  • .once 只触发一次
  • .stop 阻止冒泡
  • .prevent 阻止默认事件
  • .self
  • .passive
  • .capture 阻止捕获
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./JS/vue.js"></script>
</head>
<body>
    <div id="app">
        <button @click="warn('hello',$event)">按钮</button>
        <a href="http://www.baidu.com" @click="prevent($event)">百度</a>
        <a href="http://www.baidu.com" @click.prevent="sayHello">百度</a>
    </div>
    <script>
        const vm = new Vue({
            el:'#app',
            methods:{
                warn(text,event){
                    console.log(text);
                    console.log(event);
                },
                prevent(event){
                    if(event){
                        event.preventDefault()
                    }
                },
                sayHello(){
                    console.log('hello');
                }
            }

        }) 
    </script>
</body>
</html>

按键修饰符

  • .enter
  • .tab
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .delete
<input @keyup.enter = 'submit'>

监听事件的好处(面试题)

  1. 易读(容易查找)
  2. 无需手动销毁
  3. 不必在js中绑定事件

列表渲染

v-for

  • 基本语法 v-for="item in arr"

  • 对象的操作 v-for="item in obj"

  • 如果是数组没有id v-for="(item,index) in arr" :key='index'

  • v-for的优先级最高

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<ul>
				<li v-for="item in arr" :key = 'item.id'>id:{{item.id}} 菜名:{{item.name}}</li>
				<li v-for="item in obj">{{item}}</li>
			</ul>
		</div>
		<script type="text/javascript">
			const vm = new Vue({
				el:'#app',
				data:{
					arr:[
						// 数组
						{
							id:1,
							name:'红烧肉',
						},
						{
							id:2,
							name:'锅包肉',
						},
						{
							id:3,
							name:'烧茄子'
						}
					],
					obj:{
						//对象
						name:'john',
						age:20,
						fav(){
							console.log('handsome');
						}
					}
				}
			})
		</script>
	</body>
</html>

绑定key(先做了解)

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute

建议

在使用v-for时,给每个元素绑定key属性,有id尽量绑定id,没有绑定index。尽量是一个数值。

作用

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

v-model

你可以用 v-model 指令在表单inputtextareaselect元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。

v-model 会忽略所有表单元素的 valuecheckedselected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

文本

对于 input文本输入,绑定的是value值 input事件

<body>
		<div id="app">
			<p>{{msg}}</p>
			<input type="text" v-model="msg">
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'john'
					}
				});
		</script>
</body>

原理

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<p>{{msg}}</p>
			<input type="text" :value='msg' @input='handleInput'>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'john'
					},
                	methods:{
                        handleInput(e){
                            this.msg = e.target.value
                        }
                    }
				});
		</script>
	</body>
</html>

多行文本

与文本输入一致

复选框

对于复选框单选,绑定的是checkedchange事件

	<body>
		<div id="app">
			<label for='inp'>{{checked}}</label >
			<input id="inp" type="checkbox" v-model="checked"></div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						checked:false
					}
				});
		</script>
	</body>

原理

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<label for='inp'>{{checked}}</label >
			<input :checked='checked' type="checkbox" @change='handleChange' ></div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						checked:false
					},
                	  methods:{
                          handleChange(e){
                              this.checked = e.target.checked
                          }
                      }
			});
		</script>
	</body>
</html>

对于复选框多选,绑定到同一个数组

	<body>
		<div id="app">
			<p>{{checkedName}}</p>
			<label for='sing'>sing</label >
			<input id="sing" type="checkbox" value ='sing'v-model="checkedName" >
			<label for='dance'>dance</label >
			<input id="dance" type="checkbox" value ='dance'v-model="checkedName" >
			<label for='sleep'>sleep</label >
			<input id="sleep" type="checkbox" value ='sleep'v-model="checkedName" >
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						checkedName:[]
					}
				});
		</script>
	</body>

单选按钮

绑定checked属性和change事件

	<body>
		<div id="app">
			<input type="radio" id="one" value="One" v-model="picked">
			  <label for="one">One</label>
			  <br>
			  <input type="radio" id="two" value="Two" v-model="picked">
			  <label for="two">Two</label>
			  <br>
			  <span>Picked: {{ picked }}</span>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						picked:''
					}
				});
		</script>
	</body>

选择框

单选,绑定value属性和change事件

	<body>
		<div id="app">
			<select v-model="selected">
			    <option disabled value="">请选择</option>
			    <option>A</option>
			    <option>B</option>
			    <option>C</option>
			  </select>
			  <span>Selected: {{ selected }}</span>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						selected:''
					}
				});
		</script>
	</body>

多选 ,与复选框多选类似,绑定到一个数组

	<body>
		<div id="app">
			<select v-model="selected" multiple style="width: 50px;">
			    <option>A</option>
			    <option>B</option>
			    <option>C</option>
			  </select>
			  <br>
			  <span>Selected: {{ selected }}</span>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						selected:[]
					}
				});
		</script>
	</body>

修饰符

  • .lazy 不同步更新
  • .trim 过滤

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 ,你可以添加 lazy 修饰符,从而转为在 change 事件后进行同步。

.trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符。

侦听器watch

监听数据属性

<body>
		<div id="app">
			<input type="text" v-model="msg">
			<h3>{{msg}}</h3>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:''
					},
					watch:{
                        //监听data中的属性
						msg:function(newV,oldV){
							console.log(`新值:${newV}  旧值:${oldV}`);
						}
					}
				});
		</script>
</body>

深度监听

当数据属性较为复杂时,就需要进行深度监听。因为普通监听,监听不到

	<body>
		<div id="app">
			<h3>{{stus[0].name}}</h3>
			<button @click="change">点击</button>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'',
						stus:[{
							name:'john',
							age:18
						}]
					},
					watch:{
						stus:function(newV,oldV){
							console.log(`新值:${newV}  旧值:${oldV}`);//没有数据
						}
					},
					methods:{
						change(){
							this.stus[0].name = 'jack'
						}
					}
				});
		</script>
	</body>

深度监听

	<body>
		<div id="app">
			<h3>{{stus[0].name}}</h3>
			<button @click="change">点击</button>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'',
						stus:[{
							name:'john',
							age:18
						}]
					},
					watch:{
                        // key是属于data对象的属性名 value:监视后的行为 newV :新值 oldV:旧值
						stus:{
                            //深度监听
							deep:true,
							handler:function(newV,oldV){
								console.log(newV[0].name);
							}
						}
					},
					methods:{
						change(){
							this.stus[0].name = 'jack'
						}
					}
				});
		</script>
	</body>

计算属性computed

当模板过于复杂时,会让人难以快速识别,如:

<h3>
    {{msg.split('').reverse().join('')}}
</h3>

因此就用到了计算属性

	<body>
		<div id="app">
			<h3>{{reverseMsg}}</h3>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'hello',
					},
					computed:{
						//computed默认只有getter()
						reverseMsg(){
							return this.msg.split('').reverse().join('');
						}
					}
				});
		</script>
	</body>

优点

计算属性能够产生缓存,一旦设置了计算属性,此属性就会一直存在于内存之中,随用随取。当然,你也可以通过设置方法来达到计算属性的作用,但是需要多次调用方法。

setter()

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<h3>{{content}}</h3>
			<input type="text" v-model="content" @input="handler">
			<button @click="handleClick">获取</button>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						msg:''
					},
					computed:{
						/* content(){
							return this.msg
						} */
						content:{
							set(newVal){
								this.msg = newVal;
							},
							get(){
								return this.msg;
							}
						}
					},
					methods:{
						handler(event){
							const {value} = event.target;
							// this.msg = value;
							this.content = value;
						},
						handleClick(){
							if(this.content){
								console.log(this.content);
							}
						}
					}
				});
		</script>
	</body>
</html>

过滤器filters

处理数据

局部过滤器

只能在当前实例中使用

	<body>
		<div id="app">
			<span>{{price | myPrice('$')}}</span>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			const vm = new Vue({
					el:"#app",
					data:{
						price:10
					},
					filters:{
						myPrice:function(price,a){
							return a+price;
						}
					}
				});
		</script>
	</body>

全局过滤器

	<body>
		<div id="app">
			<span>{{msg | myReverse}}</span>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			//全局过滤器
			Vue.filter('myReverse',function(val){
				return val.split('').reverse().join('');
			})
			const vm = new Vue({
					el:"#app",
					data:{
						msg:'hello filter'
					},
				});
		</script>
	</body>