声明:只是记录,初心是为了让页面更好看,会有错误,我并不是一个会记录的人,所以有点杂乱无章的感觉,我先花点时间把视频迅速过掉,再来整理这些杂乱无章的内容
环境准备
下载vue:Vue下载
下面两个是可选的,主要是我想让控制台干净点
vue_dev_tool安装 vue_dev_tool安装
: Vue 控制台出现You are running Vue in development mode. Make sure to turn on production mode when deploying for production
Vue核心
初识Vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js" type="text/javascript"> </script>
</head>
<body>
<!-- html:5快速生成 -->
<div id="display">
欢迎来到{{name}}的网站
</div>
<div id="display">
欢迎来到{{name}}的网站
<!-- {{name}}是插值表达式,在data中找名为name的键所对应的值 -->
<!-- 插入表达式里面写的是js表达式,容器与Vue实例是一一对应的关系 -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false
// new Vue({})的{}是一个配置对象
// 这里必须写new 不写的话会报错,在vue.js的5770行的function Vue中有源报错信息
new Vue({
el:"#display",//el是element的缩写
// #display是通过id选择器来绑定,通常是使用id选择器,下面的几种要认识
// 通过类选择器来绑定:把#display换成.display即可
// document.getElementById("display")
data:{
name:"矽疑"
}
})
</script>
</body>
</html>
下面是上面代码的总结
- Vue工作必须创建一个Vue实例,并且要传入一个配置对象
- root容器里的代码被称为Vue模版
- Vue实例和容器是一一对应的
- 开发中只有一个Vue实例
- 插值表达式中只能写js表达式
- data中的数据发生改变,页面中用到该数据的地方会自动更新
-
Vue开发者工具里面的Root是Vue实例哈
最后一条的意思是
模版语法
效果我不说了
模版的理解
插值语法
就是插值表达式,用于解析标签体
的内容,语法就是{{xx}},xx会作为js表达式解析.
标签体的意思是
<a>标签体</a>
指令语法
解析标签属性、解析标签体内容、绑定事件
例如 v-bind:href='xxx’ xx会作为js表达式解析,v-bind:可缩写为:
数据绑定
单向数据绑定
- 语法:v-bind:href=“xxx” 或简写为:href
- 特点:数据只能从data流向页面
双向数据绑定
- 语法: v-model:value=“xxx” 或简写为v-model=“xx”
- 数据不仅能从 data 流向页面,还能从页面流向data
区别
- 双向绑定只能应用在表单上(收集信息的,或者说有value属性的标签上)
el与data的两种写法
el
- 直接在配置对象中写死
<script type="text/javascript">
new Vue({
//第一种写法
el:"#display",
});
</script>
2. 使用$mount来挂载
运行下面的代码
```html
Vue.config.productionTip = false;
const v = new Vue({
data:{
name:"矽疑心"
}
});
console.log(v);
控制台会输出如下所示,以$开头的是提供给程序使用的,图片第一个划红线的部分是Vue对象的缔造者(构造函数),js我不太懂,弹幕上说的是构造函数的原型方法可以被构造的实例所共用
使用mount
<div id="display">
单向数据绑定:<input type="text" v-bind:value="name">
<br/>
双向数据绑定:<input type="text" v-model:value="name">
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
Vue.config.productionTip = false;
const v = new Vue({
el:"#display",
data:{
name:"矽疑心"
}
});
console.log(v);
v.$mount("#display");//就是这个挂载的
</script>
data的
- 对象式
<script type="text/javascript">
new Vue({
el:"#root",
data:{
name:"abc",
age:19
}
})
</script>
- 函数式
<script type="text/javascript">
new Vue({
el:"#root",
data:function(){//data:function(){这部分可以换成data(){,下面的不要变
//是Vue调用这个函数
return {
name:"abc",
age:19
}
}
//不要写成箭头函数,写成箭头函数时Window对象来调用
/*
data:()=>{
return {
name:"abc",
age:19
}
}
*/
})
</script>
MVVM模型
- M:模型(Model):对应data中的数据
- V:视图(View):模版
- VM:视图模型(ViewModel):Vue实例
- data中所有属性都出现在vm身上
- vm身上所有的属性及vue原型上所有属性,在vue模版中都可以直接使用
结合代码来理解
解释第5点的意思
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="../js/vue.js" type="text/javascript"> </script>
<div id="root">
<h1>名称:{{name}}</h1>
<h1>地址:{{address}}</h1>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
name:"矽疑",
address:"安天"
}
});
console.log(vm);
</script>
</body>
</html>
观察控制台
Object.defineProperty
- 现有peson对象,要添加age属性,值为19,让其可遍历,可被修改,可被删除
<script type="text/javascript">
let number = 11
let person ={
name:'禧疑心',
sex:'女'
}
//给person添加age属性
Object.defineProperty(person,'age',{
value:19,
enumerable:true,//控制属性是否可以枚举(遍历) 默认值是false
writable:true,//控制属性是否可以被修改,默认值是false
configurable:true,//控制属性是否可以被删除,默认是false 使用delete 对象名.属性名进行测试,若删除成功就是true,反之false
}),
</script>
- 现有存放年龄的变量age,实现age与person.age的双向绑定
将如下代码(script标签要去掉)添加到Object.defineProperty中
<script>
//有人读取person.age属性的时候,get函数会调用,返回值就是age的值
//之所以是读取person.age才进入这个函数是因为在Object.defineProperty
//中第二个参数就是指明添加的属性,若添加的属性是name,那么只有读取person.name才能进入到get中
get:function(){
/*
get:function()可以写为get(),set:function(value)也一样
*/
return age;
},
//修改person.age属性的时候,set函数会调用
set:function(value)
{
age = value;
}
</script>
数据代理
通过一个对象代理对另一个对象中属性的操作(读或写)
<script type="text/javascript">
let ob1 = {x:100}
let ob2 = {y:200}
//ob2有ob1的x也有自己的y
Object.defineProperty(ob2,'x',{
enumerable:true,
get(){
return ob1.x;
},
set(value){
ob1.x = value;
}
})
</script>
Vue中的数据代理
这里有点原理性的东西,我尽可能记录清楚
假设我们的data就只有address和name两个属性,只要证明出有两条线即可
getter那条线特别好找到,就是修改data.name直接反映到页面上用到data.name的地方,
setter有点麻烦,我们知道
<script type="text/javascript">
const vm = new Vue({
data:{
name:"矽疑",
address:"安天"
}
})
//new Vue({})中的{}是一个配置对象,在Vue中可以直接通过options获取到
</script>
那么接下来需要让这个不等式成立vm.data==data,但是直接拿data拿不到,需要修改代码,修改后的代码如下所示
<script type="text/javascript">
let data = {
name:"矽疑",
address:"安天"
}
const vm = new Vue({
data
})
//new Vue({})中的{}是一个配置对象,在Vue中可以直接通过options获取到
</script>
这样就可以访问到了,vm.data == data,然后结果是false,实际上配置对象中的data是放在vm._data当中的,所以vm._data === data,这个的结果是等于true的,这个等式写全点应该是vm._data = options.data = data,这个options就是存放配置对象的,接下来就是看ppt了
事件处理
初识
<div id = "xiyi">
<button v-on:click="function3">点击1</button>
<!-- 这种方式可以传参,$event是获取原生的DOM事件对象,后面的就是传入参数了-->
<button @click="function2($event,123)">点击2</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天"
},
methods:{
function1(event){
alert(event);
},
//不要写成这个样子
// function3:()=>{
// console.log(this);//this是Window
// },
function2(event,a){
console.log(event,a);
}
}
})
</script>
写的事件处理函数反应在Vue实例对象上,如图所示
不要把事件处理函数放到data中,不会报错,但是会让Vue变慢,因为Vue会把data中的东西做一个数据代理和数据劫持,不放在data中的原因是因为函数写好了之后只用等别人来调用即可,下面一张图了解一下
总结
- 使用v-on:xxx 或@xxx 绑定事件,其中xxx是事件名
- 事件的回调函数要配置在methods对象中,最终会在vm中体现
- methods中配置的函数,不要用箭头函数,否则this不是vm
- methods中配置的函数,都是被Vue管理的函数,this的指向是vm或组件实例化对象
- @click="fun1"和@click="fun1($event)"一致,但是后者则可以传参
事件修饰符
一共有6个,前3个比较常用,一个个的来看
- prevent:阻止默认事件
<div id = "xiyi">
<!-- prevent 阻止默认事件 不加prevent的话a标签点击后默认会跳转-->
<a :href="url" @click.prevent="function1($event,1)">dianji1</a>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
function1(event,a){
// event.preventDefault();//阻止默认行为
console.log(a);
}
}
})
效果就是点击a标签不跳转
2. stop:阻止事件冒泡(即多个组件嵌套,触发内层组件时,会一一触发外层事件)
<style>
.parent{
width: 200px;height:400px;background-color: skyblue;
}
.son{
width: 100px;background-color: palegreen;margin-top:50px;
}
</style>
<div id = "xiyi">
<!-- prevent 阻止默认事件 不加prevent的话a标签点击后默认会跳转-->
<!-- stop 阻止事件冒泡 -->
<!-- 事件处理过程是先捕获后冒泡 -->
<div class="parent"
@click="function1($event,1)">
<!--button冒泡到div上,也就是子冒到父上,在子上添加stop就不会冒到父上,若div外面还有一层,那么div也需要加上stop-->
<button class="son"
@click.stop="function1($event,2)">
按钮测试</button>
</div>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
function1(event,a){
// event.preventDefault();//阻止默认行为
console.log(a);
},
function2(event,a){
console.log(event,a);
}
}
})
</script>
不加stop的效果就是点击button控制台输出2和1
加了就只输出2
- once:事件只触发一次(常用)
<div id = "xiyi">
<!-- once 事件只触发一次 -->
<button @click.once="function3('点击了一次')" >once测试</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
function3(a){
console.log(a);
}
}
})
</script>
- capture 事件的捕获模式,让其在捕获阶段就处理事件
<div id = "xiyi">
<!-- capture 使用事件的捕获方式 -->
<div class="parent" @click.capture="showInfo('parent')">
<!--让parent在捕获阶段就能处理-->
div1
<div class="son"
@click="showInfo('son')"
style="margin-top:10px">
div2
</div>
</div>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
showInfo(content){
console.log(content);
},
}
})
</script>
- self:只有event,target是当前操作的元素的时才触发事件
<div id = "xiyi">
<!-- self:只有event,target是当前操作的元素的时才触发事件 -->
<div class="parent" @click.self="showInfo()">
div1
<br/>
<button class="son"
@click="showInfo($event)"
style="margin-top:10px">
button
</button>
</div>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
showInfo(e){
// console.log(content);
console.log(e.target);//这个是查看源的
}
}
})
</script>
点击button,控制台输出如下
可以看到都是button抛出的,现在将parent修饰的div的click事件加上self修饰,代码如下所示
<!--就是只有当源是div的时候才触发click事件
-->
<div class="parent" @click.self="showInfo()">
div1
<br/>
<button class="son"
@click="showInfo($event)"
style="margin-top:10px">
button
</button>
</div>
</div>
再次点击button,效果是
6. passive:这个据说是手机或平板用的比较多,事件的默认行为立即执行,无需等待事件回调执行完毕,不加这个就是只有当事件回调函数处理完成之后才相应默认行为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>
<style>
*{
padding-top:20px;
}
.parent{
width: 200px;height:400px;background-color: skyblue;
}
.son{
width: 100px;background-color: palegreen;margin-top:150px;
}
ul{
width: 200px;height:400px;background-color: skyblue;
/* 滚动条 */
overflow: auto;
}
li{
height: 200px;
}
</style>
<div id = "xiyi">
<!-- scroll是给滚动条添加的事件
wheel是给滚动轮(鼠标上面中间的那个轮子)添加的事件
只要滚轮在动那么就触发事件,不管滚动条是否到底了
但是写成wheel且不加passive会出现滚动条不动,卡在了handle函数那里
加了就不卡
-->
<ul @scroll="handle()">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#xiyi",
data :{
name:"安天",
url:"http://notdy.top"
},
methods:{
handle(){
for(let i=0;i<1000000;i++){
console.log('#')
}
console.log('完成');
// 这个函数处理完成
// 之后才能执行默认行为
}
}
})
</script>
</body>
</html>
键盘监听事件
- Vue常见的按键别名:
回车->enter
删除->delete
退出->esc
空格->space
换行->tab 必须配合keydown来使用
上->up
下->down
左->left
右->right - Vue未提供别名的按键,但可以使用原始的key值去绑定,但注意要转为kebab-case(短横线命名)
- 系统修饰键(Ctrl,alt,shift,meta 这个就是Windows的win键)
- 配合keyup使用,按下修饰键的同时,再按下其他键,再释放其他键,事件才被触发
- 配合keydown使用,正常触发事件
- 也可以使用keyCode去指定具体的按键(不推荐)
- Vue.config.keyCodes.自定义键名 = 键码可以去定制按键别名
下面一条条的解释,解释第一条
现有文本框,实现效果:输入回车后在控制台输出文本框中输入的内容
<div id="root">
<h3>欢迎来到{{name}}的网站</h3>
<!--@keyup.enter表示松开回车键触发事件-->
<input type="text" placeholder="按下回车提示输入"
@keyup.enter = "showInfo"
>
</div>
<script type="text/javascript">
new Vue({
el:"#root",
data:{
name:"王矽疑"
},
methods:{
showInfo(e){
// @keyup.键码值
// if(e.keyCode!==13) //13是回车的键码值
return//若采用这个if那上面的@keyup.enter就改成@keyup就行,不该应该也可以,我没有试过
//console.log(e.key,e.keyCode)//拿到按键的名字和键码值
// CapsLock -> @keyup.caps-lock
console.log(e.target.value)//拿到文本框中的值
}
}
})
</script>
第二条,就比如说我按下CapsLock键后输出文本框的内容
通过e.key
拿到键名,CapsLock的键名是CapsLock但是要写成caps-lock,例如@keyup.caps-lock
第三条这个能看懂,但是如果我要实现按住Ctrl+y后输出呢?将@keyup.ctrl
改成@keyup.ctrl.y
即可
第四条不做解释
第五条
我按住键码值为220的键,别名为xie,输出内容
<div id="root">
<h3>欢迎来到{{name}}</h3>
<input type="text" placeholder="按下回车提示输入"
@keyup.xie = "showInfo"
>
</div>
<script type="text/javascript">
Vue.config.keyCodes.xie = 220
new Vue({
el:"#root",
data:{
name:"王矽疑"
},
methods:{
a(){
},
showInfo(e){
// @keyup.键码值
// if(e.keyCode!==13) //13是回车的键码值
// return
// console.log(e.skey,e.keyCode)//拿到按键的名字和键码值
// CapsLock -> @keyup.caps-lock
console.log(e.target.value)//拿到值
}
}
})
</script>
计算属性
要用的属性不存在,通过已有的属性计算得到,并且计算属性有缓存
,底层借助了Object.defineproperty方法提供的getter和setter,计算属性最终会出现在vm上
get函数在以下情况会被执行
- 初次读取时会执行一次
- 依赖的数据发生改变的时候会再次调用
下面的代码是接受用户输入姓名,输出拼接的姓名并且实时刷新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="demo">
<!-- v-model双向绑定 -->
姓: <input type="text" v-model="first">
<br/>
名: <input type="text" v-model="last">
<br/>
全名:{{fullName}}
</div>
<script type="text/javascript">
new Vue({
el:"#demo",
data:{
first:"张",
last:"三"
},
// 计算属性:由一些已有属性通过计算(一般是由函数处理)得到一个新的属性,由于新属性=计算+属性
// 所以 简称计算属性,存储在vm的computed中,他也是在vm当中的且名字就是①处的,所以可以直接从vm.属性名获取到
// 计算属性有缓存
computed:{
//①
// fullName:{ 完整的
// //Vue对象调用get 和set
// get(){
// // first 和last是直接可以在vm中获取到的
// return this.first+'-'+this.last;
// },
// // set(value){
// // const arr = value.split('-');
// // first = arr[0];
// // last = arr[1];
// // }
// }
//function当成get或者set来用
fullName:function(){
return this.first+'-'+this.last;
}
}
})
</script>
</body>
</html>
监视属性
指定属性值发生改变后执行回调函数(就是那个handler),下面代码的意思就是点击按钮在控制台输出ishot的旧值和新值,输出格式:“被修改了 oldValue->newValue”
<script src="../../js/vue.js"></script>
<div id="root">
今天天气很{{showInfo}}
<button @click="change()">点击</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
isHot:true
},
computed:{
showInfo(){
return this.isHot ?'炎热':'寒冷';
}
},
methods:{
change(){
this.isHot=!this.isHot;
}
},
//配置监视对象
watch:{
// //可以监视计算属性,把isHot换成经计算属性名就行
// isHot:{
// //当isHot被修改后会调用
// handler(oldValue,newValue){
// console.log('被修改了'+oldValue+'->'+newValue);
// },
// immediate:true//初始化让handler调用一下
// }
//简写的方式
isHot(oldValue,newValue){
console.log('被修改了'+oldValue+'->'+newValue);
}
}
})
// 监视属性名,配置监视对象
vm.$watch('isHot',{
//当isHot被修改后会调用,函数名好像还只能写成handler
handler(oldValue,newValue){
console.log('被修改了'+oldValue+'->'+newValue);
},
immediate:true
})
//下面是简写的方式
/*
vm.$watch('isHot'(newValue,oldValue)=>{
console.log(oldValue+'->'+newValue);
});
*/
</script>
- 监视的属性必须存在才能监视
- 若明确知道监视那个属性,就可以直接通过new Vue的方式传入watch配置,若不知道那就通过vm.$watch监视
深度监视
这个一般是监视多级数据中的某一个或一些发生改变之后执行回调函数
需要配置deep
- Vue的watch默认不监测对象内部值的改变(一层)
- 配置deep:true可以监测对象内部值改变(多层)
- 使用watch时根据数据的具体结构,决定是否采用深度监视
<script src="../../js/vue.js"></script>
<div id="root">
a的值是{{numbers.a}}
<br/>
<button @click="numbers.a++">点击a+1</button>
<br/>
b的值是{{numbers.b}}
<br/>
<button @click="numbers.b++">点击b+1</button>
isHot的值是{{info}}
<br/>
<button @click="change()">点击</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
isHot:true,
numbers:{
a:1,
b:1
}
},
methods:{
change(){
this.isHot=!this.isHot;
}
},
computed:{
result(){
return this.isHot?'炎热':'寒冷';
}
}
watch:{
// vue是可以监测到多级数据的变化的,但是提供的watch是不行的,需要配置deep项
// 'numbers.a':{
// handler(newValue,oldValue){
// console.log('a '+oldValue+'->'+newValue);
// }
// },
// 多级键只能是字符串类型
// 'numbers.b':{
// handler(newValue,oldValue){
// console.log('b '+oldValue+'->'+newValue);
// },
numbers:{
deep:true,//开启这个,监视多级属性
handler(newValue,oldValue){
console.log(oldValue+'->'+newValue);
}
},
}
})
</script>
watch和computed
差异
- computed能做的,watch都可以做
- 但watch可以执行异步操作
案例:输入姓名,延迟1s输出
watch可以实现,但是computed不行(我有一个想法,就是用循环去凑1s,但是这个不准),下面是watch的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>watch</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="demo">
<!-- v-model双向绑定 -->
姓: <input type="text" v-model="first">
<br/>
名: <input type="text" v-model="last">
<br/>
全名:{{fullName}}
</div>
<script type="text/javascript">
new Vue({
el:"#demo",
data:{
first:"张",
last:"三",
fullName:'张-三'
},
watch:{
first(newValue){
setTimeout(() => {
//必须写成箭头函数,写成function的话这里的this就是window
//回调函数都是js引擎调用的
//箭头函数没有this,向外找,也就是first的this,也就是vm
this.fullName = newValue+'-'+this.last;
}, 1000);
},
last(newValue){
this.fullName = this.first+'-'+newValue;
}
},
})
</script>
</body>
</html>
computed的看看
<script type="text/javascript">
new Vue({
el:"#demo",
data:{
first:"张",
last:"三"
},
computed:{
fullName(){
// return是返回给了匿名函数
//
setTimeout(() => {
//匿名函数没有this,向外找也就是vm了
return this.first+'-'+this.last;
}, 1000);
// return 1;
}
},
})
</script>
class与style绑定
class绑定
- :class=“xxx”,样式的类名不确定,需要动态指令,
字符串写法
- :class=“[‘class1’,‘class2’,‘class3’]”,class是列表中的组合,可能是三个都用上了,也有可能是三个都用不上,列表的元素的组合。一般是把双引号的内容在data中声明一个数组来存储.这个是
数组写法
.适用于要绑定的样式个数不确定、名字也不确定 - :class=“classObj” classObj是对象,这个是
对象写法
,适用于要绑定的样式个数确定,名字确定,但要动态决定用不用
classObj:{
a:false,//false就是不用,反之就是用
b:false
//4种情况
/*
a b
f f
f t
t f
t t
*/
}
style绑定
这个用的不多
- :style = “{fontSize:fsize+‘px’}”
- :style = “objName”,
objName是放在data中的一个样式对象,如
objName:{
//样式对象就是key是css属性
color:red,
fontsize:'19px'
}
- :style=“[objName1,objName2]”,是第二种的嵌套写法
条件渲染
下面的两个都是决定元素显示还是隐藏
v-show
,若v-show的值为true就是显示,反之隐藏。一般是把flag(我一般是把这个作为控制元素的显示还是隐藏的)写在data当中,用户点击某某时,注册对应的事件,让flag发生改变
适用于高频率
v-if与v-else-if 与v-else
v-if是把元素都删了,v-show是借助display:none的,v-if适合低频率,因为v-if直接操作的是DOM,v-else不用条件哈,并且可以与template配合使用,template就是模板,一般是作为一个容器来使用,但是页面渲染的时候源码里面没有template
列表渲染
v-for
遍历元素的,看例子把
- 用于展示列表数据
- 语法: v-for=“(item in items) in xxx” :key=“yy”
- 可遍历:数组、对象、字符串(用的很少),指定次数(用的更少)
key的作用和原理
过滤和排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<input type="text" v-model="keyWord">
<li v-for="r in res" :key="r.id">
{{r.name}}-{{r.age}}-{{r.sex}}
</li>
</div>
<script src="../../js/vue.js"></script>
<script type="text/javascript">
//#region watch实现
// new Vue({
// el:"#root",
// data:{
// people:[
// {id:1,name:'马春梅',age:20,sex:'女'},
// {id:2,name:'周冬雨',age:20,sex:'男'},
// {id:3,name:'金玟岐',age:20,sex:'女'},
// {id:4,name:'王矽疑',age:20,sex:'女'},
// {id:5,name:'周杰伦',age:20,sex:'男'},
// ],
// keyWord:'',
// res:[]
// },
// watch:{
// keyWord:{
// immediate:true,//为false会出现第一次不输入的时候不出现people的内容
// handler(newValue){
// // 过滤器会产生一个新的数组,
// this.res = this.people.filter((p)=>{
// //条件是留下来过滤后的 不是过滤掉的
// return p.name.indexOf(newValue)!==-1;
// })
// }
// }
// }
// })
//#endregion
//#region computed实现
new Vue({
el:"#root",
data:{
people:[
{id:1,name:'马春梅',age:20,sex:'女'},
{id:2,name:'周冬雨',age:20,sex:'男'},
{id:3,name:'金玟岐',age:20,sex:'女'},
{id:4,name:'王矽疑',age:20,sex:'女'},
{id:5,name:'周杰伦',age:20,sex:'男'},
],
keyWord:'',
},
computed:{
res(){
//计算属性是要靠返回值的
const arr = this.people.filter((p)=>{
//条件是留下来过滤后的 不是过滤掉的
return p.name.indexOf(this.keyWord)!==-1;
})
if(this.sortType){
//排序
arr.sort((p1,p2)=>{
return this.sortType==1?p1.age-p2.age:p2.age-p1.age;
})
}
return arr
}
}
})
//#endregion
</script>
</body>
</html>
监视数据
原理
通过setter实现监视
且要new Vue时传入要监测的数据,.对象中后追加的属性,Vue默认不做响应式处理
如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或vm.$set(target,propertyName/index, value)
例如Vue.set(this.student,‘gender’,‘男’)
怎么监测数组中的数据
通过包裹数组更新元素的方法实现,本质就是做了两件事:
-
调用原生对应的方法对数组进行更新。
-
重新解析模板,进而更新页面。
修改数组中某个元素一定要用如下方法
- 使用这些API
-
- push() 追加到最后
- pop() 删除最后一个
- shift() 删除第一个并返回第一个
- unshift() 把他的值插入到第一个
- splice() 这个用到了查去
- Vue.set()或 vm.$set() (例如: this.$set(this.student.hobby,0,‘开车’),把hobby第一个元素改为开车)
- sort()
- reverse()
如果我们用的不是上面的API,把结果放回源
Vue.set()或 vm.$set()都不能往vm或vm的根数据对象(_data)上添加属性!!!
数据劫持浅显的理解就是你data里面的数据被vue添加了一些setter和getter,被Observer包裹着
收集表单数据
这个我只记录我不会的
v-model的三个修饰符
- lazy:失去焦点再收集数据
- number:输入字符串转为有效数字
- trim:输入首尾空格过滤
过滤器
在bootstrap中搜索day.js下载
需要配置filters项,过滤器本质就是一个函数
语法
- 注册过滤器
- 全局: Vue.filter(‘name’,callback)
- 局部:new Vue(filters:{xxxx})
- 使用: {{xxx | 过滤器名}} 或v-bind:属性 =“xxx| 过滤器名”,v-bind可以缩写为:
代码
<div id="root">
<!-- time默认会传参 -->
<!-- time作为参数传给timeFormater YYYY_MM_DD传给str-->
<!--过滤器链 timeformater的结果给mysub -->
{{time | timeFormater('YYYY_MM_DD')}}
<!-- 这个基本上不用 但是只能用于自定义属性-->
<h3 :x="info | test"></h3>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script>
<script src="../../js/vue.js"></script>
<script type="text/javascript">
//全局过滤器
Vue.filter('test',function(value){
return value.slice(0,4)
})
new Vue({
el:"#root",
data:{
time:1621561377603,
info:"这是一个测试"
},
//这里面的都是局部过滤器
filters:{
// str="YYYY年MM月DD日 HH:mm:ss"表示默认值为YYYY年MM月DD日 HH:mm:ss
timeFormater(value,str="YYYY年MM月DD日 HH:mm:ss"){
return dayjs(value).format(str)
},
}
})
</script>
v-text 与v-html
v-text
向其所在的结点中渲染文本内容(直接把v-text的值放在标签体中),但是会替换掉结点的的内容如下面的代码
info=“
hello
”<!-- 这个是可以的-->
测试:{{info}}
<!-- 标签体里面的写与不写都一样-->
<h3 v-text="info">测试</h3>
v-html
info=“
hello
”与v-text相比会解释其中的内容
<!-- 这个是可以的-->
测试:{{info}}
<!-- 标签体里面的写与不写都一样-->
<h3 v-html="info">测试</h3>
v-cloak
没有值,Vue实例创建完毕并接管容器后,会删掉v=cloak属性,
使用css配合v-cloak可以解决网速慢时页面展示出{{xxxx}}的问题
一般需要配合下面的css属性来用
<style>
[v-cloak]{
display:none;
}
</style>
v-once
- v-once所在节点在初次动态渲染后,就视为静态内容了
- 以后数据改变不会引起v-once所在结构的更新,可以用于优化性能
data:{
a:1
}
<div id="root">
<h2 v-once>初始化a的值时:{{a}}</h2>
<h2> 当前的a值是{{a}}</h2>
<button @click="a++">点我a+1</button>
</div>
v-pre
可以跳过其所在节点的编译过程,常应用于没有使用指令语法和插值语法的节点,会加快编译
<div id="root">
<h2 v-pre>静态内容</h2>
<h2 v-once>初始化a的值时:{{a}}</h2>
<h2> 当前的a值是{{a}}</h2>
<button @click="a++">点我a+1</button>
</div>
自定义指令
指令定义时不加v-,但使用时要加v-,
指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
对象式
若需要在以下时间点中做点什么东西,则需要用对象式
- 元素与指令成功绑定时 也就是bind函数
- 指令所在元素被插入页面时调用时 也就是inserted函数
- 指令所在模板结构被重新解析时 也就是update函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h2>当前的t值是:<span v-text="t"></span></h2>
<button @click="t++">t+1</button>
<hr>
<input type="text" v-fbind:value="t">
</div>
<script src="../../js/vue.js"></script>
<script type="text/javascript">
//全局指令
/*
对象式的写法
Vue.directive('name',{
//指令与元素成功绑定时(一上来)
bind(element,binding){...},
//指令所在元素被插入页面时
inserted(element,binding){...},
//指令所在的模板被重新解析时
update(element,binding){....}
}
函数式的写法
Vue.directive('name',function(element,binding)
{....})
*/
new Vue({
el:"#root",
data:{
t:12
},
/*
directives:{
若指令名是由多个单词组成的,那么单词之间要以-分割,如指令名为bigNumber
那么需要写成
'big-number':function(element,binding){..}
或者
'big-number'(element,binding){...}
之所以要以单引号引起来是因为vue的key是字符串类型,如果没有-的话,可以不用引号
}
*/
directives:{
//这个是对象式的 局部
fbind:{
//指令与元素成功绑定时调用 一上来
bind(element,binding){
element.value = binding.value
//bind和update里面的内容基本上是一致的
},
//指令所在元素插入页面中调用
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时调用
update(element,binding){
element.value = binding.value
}
}
}
})
</script>
</body>
</html>
函数式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h2>当前的t值是:<span v-text="t"></span></h2>
<h2>放大10倍后t是:<span v-product="t+1+2+3"></span></h2>
</div>
<script src="../../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:"#root",
data:{
t:12
},
directives:{
//那么product函数什么时候会被调用?
// 1. 指令与元素成功绑定时
// 2. 指令所在的模板被重新解析时
//element是绑定的html元素,这里就是span了
//binding里面有些属性是我们需要用到的
// expression 表达式 这里就是t+1+2+3
// value 就是绑定的值也就是t 这里就是12
product(element,binding){
element.innerText = binding.value * 10
}
}
})
</script>
</body>
</html>
生命周期
引出
需求:要让一个组件的透明度由1逐渐到0,再由0逐渐到1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>引出生命周期</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
生命周期:
1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
3.生命周期函数的名字不可更改,函数的具体内容是根据需求编写的。
4.生命周期函数中的this指向是vm 或 组件实例对象。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2 v-if="a">你好啊</h2>
<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
a:false,
opacity:1// 设置元素的透明度的 1:完全不透明 0:完全透明
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
setInterval(() => {
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
})
//通过外部的定时器实现(不推荐)
/* setInterval(() => {
vm.opacity -= 0.01
if(vm.opacity <= 0) vm.opacity = 1
},16) */
</script>
</html>
分析
那张长图
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>分析生命周期</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<!-- 那一张长图中的Compile el's outerHTML as template的解释:outerHTML就是容器(这里就是div)里面的东西(含容器本身)
x属性是在容器里面的,若他被解析就证明了outerHTML含容器本身
innerHTML是容器里面的东西(不含容器本身) 这个我不确定
-->
<div id="root" :x="n">
<!-- <h2 v-text="n"></h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
<button @click="bye">点我销毁vm</button> -->
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
//template:把该配置项的值放到el所绑定的容器里面
// ``是ES6的一个新的东西,因为一行写不下去,所以用``,若用''或""会报错
template:`
<div id="root"> 这里必须要有一个容器,只要能起到容器的作用就行,直接用id=root的方式,解析后id依然会等于root
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
</div>
`,
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
bye(){
console.log('bye')
this.$destroy()
}
},
watch:{
n(){
console.log('n变了')
}
},
beforeCreate() {
console.log('beforeCreate')
debugger//程序走到这里就停了,就是断点
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
},
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
},
})
</script>
</html>
总结
文章来源:https://www.toymoban.com/news/detail-669392.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>引出生命周期</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息。
2.销毁后自定义事件会失效,但原生DOM事件依然有效。
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
this.$destroy()
// clearInterval(this.timer) 这里写可以,但是不推荐,推荐写在beforeDestory中
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
beforeDestroy() {
clearInterval(this.timer)
console.log('vm即将驾鹤西游了')
},
})
</script>
</html>
一些原则
- 被Vue管理的函数,要写成普通函数,这样this指向的是vm或实例化对象
- 不被Vue管理的函数(定时器,ajax,Promise的回调函数)最好写成箭头函数,这样this指向的才是vm或组件实例对象
一些工具的东西
关于Open With Live Server
若访问的是根目录,就是当前目录,比如我的当前目录是文章来源地址https://www.toymoban.com/news/detail-669392.html
- STUDYVUE
-
- js
-
-
- vue.js
-
-
-
- vue.min.js
-
-
- page
-
-
- first.html
那么访问http://127.0.0.1:5500/,会得到下面的样子
- first.html
-
到了这里,关于Vue2+Vue3笔记(尚硅谷张天禹老师)day01的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!