Vue
创建一个简单的vue
<!--准备容器-->
<div id="app">
<!--插值语法 {{xxx}}-->
<h1>hello {{name}}</h1>
</div>
<script src="js/vue2.7.15.js"></script> //引入vue
<script type="text/javascript">
//1.创建vue实例
const vm = new Vue({
el:'#app', //绑定容器
data:{
//存储数据,数据在容器中使用
name:'猿究院'
}
});
</script>
模板语法
<!--插值语法 {{xxx}}-->
<h1>hello {{name}}</h1>
<!-- 指令语法 v-text 操作文本-->
<h2 v-text="name"></h2>
<!-- 指令语法 v-bind 属性定义-->
<a v-bind:href="url">点我跳转</a>
<!--简写形式 :xxx == v-bind:xxx -->
<input :value="name" />
vue中el和data的两种写法
/**
* el写法
* 1.vm的el属性 >>> el:'#app', //绑定容器
* 2.vm的$mount方法 >>> vm.$mount('#app')
*/
/**
* data写法
* 1.data对象 data:{xxx:{}}
* 2.data函数 返回值是对象 data(){return {}}
* data函数可以避免数据的同步,造成一处修改,全部改变
*/
<script src="js/vue.js"></script>
<script type="text/javascript">
//1.创建vue实例
const vm = new Vue({
// el:'#app', //绑定容器
data(){
//存储数据,数据在容器中使用
return{
name:'猿究院',
url:'http://www.apesource.com'
}
}
});
vm.$mount('#app') //第二种el写法
</script>
数据绑定
两种方式
单项数据绑定:<input type="text" :value="name"/> <br>
双项数据绑定:<input type="text" v-model:value="name"/>
Object.defineProperty
定义:
Object.defineProperty()方法会直接在一个对象上定义一个新的属性 或者 修改一个对象的现有属性,并返回此对象
参数
Object.defineProperty(obj,prop,descriptor) 有三个参数
- obj 要定义的属性的对象
- prop 要定义或者修改的属性名称
- descriptor 要定义或者修改的属性的描述(内容)
控制属性
- enumerable:true, //控制属性是否可以遍历 默认 false
- writable:true, //控制属性是否可以被修改 默认false
- configurable:true //控制属性是否可以删除 默认false
返回值
返回 传递函数的对象
<script type="text/javascript">
let person ={
name:'张三',
sex:'男'
}
// Object.defineProperty(person,'age',{
// value:25,
// enumerable:true, //控制属性是否可以遍历 默认 false
// writable:true, //控制属性是否可以被修改 默认false
// configurable:true //控制属性是否可以删除 默认false
// });
Object.defineProperty(person,'age',{
// 当有人读取person 的 age属性时
//get函数就会被触发,并且返回值
get(){
return this.age;
},
// 当有人写入person 的 age属性时
//set函数就会被触发,并且传入参数,修改属性
set(value){
console.log('修改内容')
return this.age = value;
}
})
console.log(person.age)
</script>
模拟vue的双向绑定
<input type="text" id="ipt">
<div id="contain"></div>
<script>
let oIn = document.getElementById("ipt");
let oDiv = document.getElementById("contain");
let text;
window.data={};
// 添加监听器,通过监听器来获取数据的改变
oIn.addEventListener('input',function (e) {
//获取当前input的value属性
window.data.value = e.target.value;
})
//通过Object.defineProperty()方法来实现数据绑定
Object.defineProperty(window.data,'value',{
get(){
return this.value;
},
set(value){
oDiv.innerHTML = value;
}
})
</script>
事件
v-on:xxx ( 简写形式:@xxx ) 事件指令语法
<div id="root">
<button v-on:click="showInfo">点击试试</button><br>
<button @click="showInfo">点击试试</button>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data(){},
methods:{
showInfo(){
console.log("执行方法")
}
}
});
vm.$mount('#root');
</script>
事件修饰符
<div id="root">
<!--@click.prevent 取消默认行为-->
<a @click.prevent="showInfo" :href="url">点我试试</a>
<div class="demo1" @click="showInfo" >
<!--@click.stop 阻止冒泡-->
<button @click.stop="showInfo">按钮</button>
</div>
<!--只执行一次-->
<button @click.once="showInfo">按钮!!</button>
<!--反转冒泡顺序-->
<div class="box1" @click.capture="showMsg('A')">
div1
<div class="box2" @click="showMsg('B')">div2</div>
</div>
<!--wheel.passive 事件的默认行为立即执行,无序等待事件的回调-->
<ul class="list" @wheel.passive="demo">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
url:'http://www.apesource.com'
};
},
methods:{
showInfo(){
console.log("执行方法")
},
showMsg(num){
console.log(num)
},
demo(){
for (let i = 0; i < 1000; i++) {
console.log("执行完毕")
}
console.log("@_@")
}
}
});
vm.$mount('#root');
</script>
键盘事件
.enter (13 不建议使用) 回车时触发
.esc 退出
.delete 删除 1.backapace 2.delete
.space 空格
<div id="root">
<input type="text" @keydown="demo" v-model:value="name"/>
<input type="text" @keydown.enter="demo" v-model:value="name"/>
<input type="text" @keydown.delete="demo" v-model:value="name"/>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
name:'apesource'
};
},
methods:{
demo(event){
console.log(event.key,this.name)
// console.log("+++",event.keyCode)
}
}
});
vm.$mount('#root');
</script>
计算属性
1.有缓存,可以二次复用
2.当参与计算的属性发生改变时,会再次执行
3.当需要一个属性但不存在时,需要通过已有属性计算的新属性
<div id="root">
姓:<input type="text" v-model:value="fName"/><br>
名:<input type="text" v-model:value="lName"/>
<hr>
<h1>姓名{{fullName}}</h1>
<h1>姓名{{fullName}}</h1>
姓名:<input type="text" v-model:value="fullName"/>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
fName:'',
lName:'',
};
},
methods:{},
computed:{
// 1.简写计算属性 只能读
// fullName(){
// return this.fName +"-"+ this.lName;
// }
fullName:{
get(){
return this.fName +"-"+ this.lName;
},
set(value){
let arr = value.split("-");
this.fName = arr[0];
this.lName = arr[1];
}
}
}
});
vm.$mount('#root');
</script>
监听器
两种方式
1.在创建Vue实例时,通过watch属性实现
2.vm.$watch实现
//1.watch:{}
// watch:{
// // 'nums.a':{
// // //初始化时监视属性
// // immediate:true,
// // handler(newValue,oldValue){
// // console.log(newValue,oldValue)
// // }
// // }
// nums:{
// //初始化时监视属性
// immediate:true,
// deep:true, //深度监视
// handler(newValue,oldValue){
// console.log(newValue,oldValue)
// }
// }
// }
});
// 2.vm.$watch
vm.$watch('nums',{
immediate: true,
deep: true,
handler(newValue, oldValue) {
console.log(newValue, oldValue)
}
});
样式绑定
class样式
-
:class=‘xxx’ xxx可以是字符串 数组 对象
- 字符串 用于类名不确定
- 对象 要绑定多个样式,个数不确定 名字不确定、
- 数组 用于 绑定多个样式,个数确定,名字确定,但是不确定用不用
style 样式
- :style=“{fontSize:xxx}” xxx是动态值
- :style=“[a,b,c]” a b c对象
- a == {fontSize:xxx,…}
<style>
.basic {
width: 400px;
height: 100px;
border: 1px solid black;
}
.demoA {
border: 4px solid red;
background-color: orange;
}
.demoB {
border: 4px dashed pink;
background-color: gray;
}
.demoC {
background-color: skyblue;
}
.box1 {
background-color: yellow;
}
.box2 {
font-size: 30px;
text-shadow: 2px 2px 10px red;
}
.box3 {
border-radius: 20px;
}
</style>
<body>
<div id="root">
<div class="basic" :class="mood" @click="changeMood">
{{name}}
</div>
<div class="basic" :class="classArr">
{{name}}
</div>
<div class="basic" :class="classObj">
{{name}}
</div>
<div class="basic" :style="styleArr">
{{name}}
</div>
<div class="basic" :style="styleObj">
{{name}}
</div>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
name:'猿究院',
mood:'demoC',
classArr:[ 'box1','box2'],
classObj:{
box1:true,
box2:false,
box3:true
},
styleObj:{
fontSize:'50px',
color:'red'
},
styleArr:[
{
fontSize:'50px',
color:'green'
},
{
backgroundColor:'red'
}],
};
},
methods:{
changeMood(){
const arr = ['demoA','demoB','demoC']
const index = Math.floor(Math.random()*3);
this.mood = arr[index];
}
}
});
vm.$mount('#root');
</script>
页面渲染
条件渲染
- v-if 适合切换频率低的场景不展示DOM时会直接移除DOM元素
注意: v-if v-else-if v-esle 使用时结构不能被打断 - v-show 适合切换频率高的场景不展示DOM元素时,DOM元素不被移除
仅仅是使用样式隐藏了
<!-- v-if -->
<!-- v-show -->
<div id="root">
<button @click="count++">count++</button>
<h2>{{count}}</h2>
<hr>
<h2 v-show="count==5">{{count}}</h2>
<hr>
<h2 v-if="count == 1">{{count}}</h2>
<h2 v-else-if="count == 2">{{count}}</h2>
<h2 v-else>其他</h2>
列表渲染
-
v-for指令< li v-for=“(item,index) in xXX” :key=“yyy”>
-
key可以是index也可以是遍历元素的唯一标识
-
可以遍历数组对象字符串指定次数
<!--遍历数组-->
<ul>
<li v-for="(stu,index) in students" :key="stu.sNo">
{{index}} - {{stu.name}} - {{stu.sNo}}
</li>
</ul>
<!--遍历对象-->
<ul>
<li v-for="(value,k) in person" :key="k">
{{k}} - {{value}}
</li>
</ul>
<!--遍历字符串-->
<ul>
<li v-for="(char,index) in str" :key="index">
{{index}} - {{char}}
</li>
</ul>
<!--循环次数-->
<ul>
<li v-for="(number,index) in 5">
{{index}} - {{number}}
</li>
</ul>
key的作用
- 虚拟DOM中的key的作用,key是虚拟DOM中对象的标识
- 当数据发生改变时,Vue会根据{新的数据}生成{新的虚拟DOM}
- 随后Vue会进行新的虚拟DOM与旧的虚拟DOM的差异比较
<!--没有key 或设置key为index-->
<ul>
<li v-for="(stu,index) in students" :key="index">
{{stu.sNo}} - {{stu.name}}
<input type="text"/>
</li>
</ul>
<!--设置key-->
<ul>
<li v-for="(stu,index) in students" :key="stu.sNo">
{{stu.sNo}} - {{stu.name}}
<input type="text"/>
</li>
</ul>
<button @click="addStudent">添加毛笔</button>
总结
-
旧的虚拟DOM中找到了与新的虚拟DOM相同的key
- 如果虚拟DOM中的内容没有发生改变,则直接使用旧的虚拟DOM
- 如果虚拟DOM中的内容发生改变,则生成新的真实DOM,替换旧的真实DOM
-
旧日的虚拟DOM中未找到与新的虚拟DOM相同的key
- 创建新的真实DOM,渲染到页面
用index作为key的问题?
- 如果对数据进行逆序的操作(添加删除)等破坏顺序的操作,会产生没有必要的真实DOM更新
- 如果包含有输入类型的DOM,会产生错误的DOM更新
列表排序、过滤
filterStudents(){
arr = this.students.filter(item =>{
return item.name.indexOf(this.keyWord) != -1;
})
if (this.sortType){
arr.sort((s1,s2)=>{
return this.sortType == 1 ? s1.age - s2.age :s2.age - s1.age
})
}
return arr;
}
列表案例
<div id="root">
<h2>学生信息</h2>
<button @click="student.age++">age+1</button>
<button @click="addSex">新增性别</button>
<button @click="addFristFriend">列表首位添加朋友</button>
<button @click="updateFriendName">修改第一位朋友的姓名为老刘</button>
<button @click="addHobby">添加一个爱好</button>
<button @click="updateHobby">删除并修改第二个爱好</button>
<button @click="filterHobbySmoke">过滤爱好中的抽烟</button>
<hr>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>爱好:</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h3>朋友:</h3>
<ol>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} - {{f.age}}
</li>
</ol>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
student:{
name:'李四',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'张三',age: 20},
{name:'王五',age: 30}
]
}
};
},
methods:{
addSex(){
this.$set(this.student,'sex','男');
},
addFristFriend(){
this.student.friends.unshift({name: '赵六',age:63});
},
updateFriendName(){
this.student.friends[0].name = '老刘';
},
addHobby(){
this.student.hobby.push('骑马');
},
updateHobby(){
this.student.hobby.splice(1,1,'美人');
},
filterHobbySmoke(){
return this.student.hobby = this.student.hobby.filter(item =>{
return item !='抽烟';
})
}
}
});
vm.$mount('#root');
</script>
数据接收
页面
<form action="#" method="post" @submit.prevent="demo" >
账号:<input v-model="userInfo.account" type="text" /> <br/><br/>
密码:<input v-model.trim="userInfo.password" type="password" /> <br/><br/>
年龄:<input v-model="userInfo.age" type="number" /> <br/><br/>
性别:<label><input v-model="userInfo.sex" type="radio" name="sex" value="男" /> 男</label>
<label><input v-model="userInfo.sex" type="radio" name="sex" value="女" /> 女</label><br/><br/>
爱好:<label><input v-model="userInfo.hobby" type="checkbox" value="0" /> 吃 </label>
<label><input v-model="userInfo.hobby" type="checkbox" value="1" /> 喝</label>
<label><input v-model="userInfo.hobby" type="checkbox" value="2" /> 嫖</label>
<label><input v-model="userInfo.hobby" type="checkbox" value="3" /> 赌</label>
<br/><br/>
城市:<select v-model="userInfo.city">
<option value="">请选择</option>
<option value="xian">西安</option>
<option value="lanzhou">兰州</option>
<option value="xining">西宁</option>
<option value="lasa">拉萨</option>
<option value="yinchuan">银川</option>
</select> <br/><br/>
其他信息:<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
<input v-model="userInfo.agree" type="checkbox" /><a>我已阅读xxxx</a> <br/>
<button type="submit">提交</button>
</form>
接收参数
data() {
return {
userInfo:{
account:'',
password:'',
age: 18,
sex:'男',
hobby:[],
city:'xian',
other:'',
agree:''
}
};
},
methods:{
demo(){
console.log(JSON.stringify(this.userInfo))
return ;
}
}
过滤器
<div id="root">
<h2>当前时间戳:{{time}}</h2>
<h2>转换后的时间:{{time | timeFormater()}}</h2>
<h2>转换后的时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}</h2>
<h2>转换后的时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss') | strTime}}</h2>
</div>
<script src="js/vue.js"></script>
<script src="js/dayjs.min.js"></script>
<script type="text/javascript">
//全局过滤器
Vue.filter('strTime',function (value,str) {
return value.slice(0,11)
})
const vm = new Vue({
data() {
return {
time:1702370485000 //时间戳
};
},
//局部过滤器
filters:{
timeFormater(value,str = 'YYYY MM DD$HH:mm:ss'){
return dayjs(value).format(str)
}
}
});
vm.$mount('#root');
</script>
指令
常见指令
/**
* 指令
* v-bind
* v-model
* v-for
* v-if
* v-else-if
* v-else
* v-show
* v-text
* v-html 不会使用
* v-cloak 没有值
* 本质是一个特殊的属性 Vue的实例
* 创建完毕并接管容器后 会删除v-cloak属性
* **** 需要css的配置 解决网速慢时 页面展示{{}}的问题
* v-once 所在的节点 初次被渲染后,就视为静态内容
* v-pre 跳过所在的节点的编译过程
*/
<style>
[v-cloak]{
display: none;
}
</style>
<div id="root">
<div v-text="name">这是文本内容</div>
<div v-html="str"></div>
<div v-cloak>{{name}}</div>
<div v-once>{{name}}</div>
<div v-pre>{{name}}</div>
</div>
自定义指令
<div id="root">
<h2>h的值:<span v-text="num"></span></h2>
<h3>放大h的值(*2):<span v-big="num"></span></h3>
<button @click="num++">num++</button>
<input type="text" v-fbind="num" />
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
data() {
return {
num:1
};
},
methods:{},
//1.创建实例时,添加directives对象
directives:{
//自定义指令
big(element,binding){
// console.log(element,binding);
element.innerText = binding.value*2;
},
fbind:{
bind(element,binding){
console.log("bind")
element.value = binding.value *2;
},
inserted(element,binding){
console.log("inserted")
element.focus()
},
update(element,binding){
console.log("update")
element.value = binding.value *2;
}
}
}
});
//2. Vue.directive(指令名,function)
Vue.directive('fbind',{
//指令与元素成功绑定时执行(一进来)
bind(element,binding){
console.log("bind")
element.value = binding.value *2;
},
//指令所在的元素被载入页面时执行
inserted(element,binding){
console.log("inserted")
element.focus()
},
//指令所在的模板被解析时
update(element,binding){
console.log("update")
element.value = binding.value *2;
}
})
vm.$mount('#root');
</script>