课程目标
<div class='app'>
<!-- vue显示数据,需要使用模板 {{js的表达式}} -->
我的名字叫:{{username}},我的年龄是:{{age+1}},我喜欢很多运动,比如:{{hobby[0]}}
<button @click="change">点击试一试</button>
<h1>{{username}}的性别是{{sex}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 0. 创建vue实例
const app = new Vue({
// 1. 挂载点
el:'.app',
// 2. 数据【格式是对象格式】
data:{
username:'jack',
age:20,
sex:'男',
hobby:['篮球','足球','羽毛球']
},
// 3. 方法:我们要干的事情,都放在methods中
methods:{
uppercase:function(){ // uppercase = 函数名
console.log('我要变成大写');
},
lowercase(){ // 简写形式
console.log('我要变成小写');
},
change(){
// 事件中的this,指向的是vue本身
this.age++;
console.log(this.age);
}
},
// 4. 用于计算的属性
computed:{
totlePrice:function(){
console.log('计算');
}
}
})
</script>
数据
let vm = new Vue({
el:'#app',
data: {
msg: "hello"
}
})
模板
<!-- 显示数据 -->
<h1>{{msg}}</h1>
<!-- 计算数据 -->
<h1>{{msg - 8}}</h1>
注意:写插值语句的时候,只有的id=app的元素下面才可以使用插值语句,所以,尽可能创建一个标签,将所要渲染的数据,都写入当前标签中
指令的属性值为js表达式
v-html:类似于原生中的innerHTML,能够解析标签 <标签 v-html=“text”></标签> 给标签添加html结构text v-text:类似于原生中的innerText,不能解析标签,只能原样输出文本 跟插值语句的用法是一样的 <标签 v-text=“text”></标签> 给标签添加文本text <标签 v-html=“text”></标签> 给标签添加标签和文本
可以解析html标签 可以将html代码显示插值表达式中,并把内容当作html处理
<div>{{msg2}}</div>
<div v-text="msg2"></div>
<div v-html="msg2"></div>
<script>
let vm = new Vue({
el:"#app",
data: {
msg:"hello",
msg2:'<h1>我是一个h1标签,我本身自带的有样式,可以进行文字变大加粗</h1>';
}
})
</script>
注:v-html也会覆盖标签中间的所有内容,所有通过属性获取内容的方式都会将原来标签中的数据进行覆盖
不能解析html标签 v-text=“msg” 和 {{msg}} 用法是一样的,显示的效果是一样的 区别在于: v-tex t会覆盖元素中原本的内容,但是,插值表达式,只会替换自己的这个占位符,不会把整个元素的内容清空
<h1 v-text="msg"></h1>
语法结构:v-bind=“type” 简写形式: :=“type”
绑定动态属性
<h1 title="msg">1111</h1>
<h1 v-bind:title="msg">2222</h1>
<h1 :title="msg">2222</h1>
<img id="imgs" src="./demo.jpg" v-bind:title="title">
</body>
<script>
let app = new Vue({
el:'#imgs',
data:{
title:'这是一张图片'
src:'./demo.jpg',
attribute: 'id'
}
})
</script>
<img id="imgs" src="./demo.jpg" v-bind:title="title+src">
<!-- 正常写法 -->
<img v-bind:src='src' v-bind:title="title"/>
<!-- 简写法 -->
<img :src='src' :title="mytitle"/>
给div标签添加一个id,id名称为div1
<div :[k]=divname>现在都有了!</div>
注:只要是给标签的属性数据绑定,也是使用v-bind
语法格式:
标准结构:<div v-on:事件名称="methods中的方式"></div>
简写形式:<div @事件名称="methods中的方式"></div>
扩展:@符号,称为是语法糖; 什么是语法糖? 指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。 在不改变其功能的情况下,通过改变代码的写法,让代码更具有可读性,更容易理解,就相当于汉语里的成语。 用更简练的言语表达较复杂的含义。在得到广泛接受的情况之下,可以提升交流的效率。
vue中常见的语法糖: v-bind : v-on @ v-on 后面的修饰符也是语法糖
js数据
var vm = new Vue({
el: '#app',
data: {
isShow: false,
msg: '1111'
},
methods: {
//没有参数的绑定
show(){
this.isShow = true;
},
//有参数的绑定
change(newVal){
this.msg = newVal;
},
//获取事件对象
get(e){
console.log(e);
},
//获取事件对象
get(newVal,e){
this.msg = newVal.isShow;
console.log(e);
}
}
});
传统添加事件的方式
document.getElementById('btn').onclick=function(){
alert('hello world')
}
模板
<p v-on:click="show">鼠标点击显示</p>
<p v-on:mouseover="show">鼠标悬浮显示</p>
<p class="box" @touchmove="get">改变msg</p>
<!-- 缩写形式 @ 冒号也可以省略 -->
<p @click="show">显示</p>
<p @click="change('hello')">改变msg</p>
event
<!-- 在事件中获取 -->
<button v-on:click="show">获取event</button>
<!-- 在标签中获取 -->
<button @click='getEve("ok",$event)'>从标签中传递event</button>
<script>
let app = new Vue({
el:'#app',
data:{
event:'click'
},
methods:{
show:function(event){ // 标准格式
console.log(event.target);
},
show(event) { // 简写格式
console.log(event.target);
},
getEve(msg,ev) { // 带参数的事件
console.log(msg,ev);
}
}
})
// 注意:如果出现名字相同的事件,不会报错,会执行后面的事件
</script>
<button @[ev]="get">动态事件编写</button>
<script>
let app = new Vue({
el:'#app',
methods:{
get(){
console.log(event.target.innerText);
}
}
})
</script>
案例:点击按钮,让元素+1
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>显示数量:{{ counter }} </p>
</div>
<script>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
</script>
总结知识点:
@click.stop= “” 阻止事件冒泡 @click.prevent=“” 阻止默认事件 @click.capture=“inner” 添加事件捕获 @click.self=“” 只给某个元素添加事件 @click.once=“” 事件只触发一次 @keyup.13=“” 键盘修饰符 @keyup.enter.13 = “” 按键修饰符
<div class="app">
<div class="warp" @click="warp">外层div
<div class="inner" @click.stop="inner">内层div</div>
</div>
</div>
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
inner(){
console.log('inner');
},
warp(){
console.log('warp');
}
}
})
</script>
<!-- a标签默认行为 -->
<a href="http://www.baidu.com" @click.prevent="gotaobao">baidu</a>
<!-- 表单默认行为 -->
<form action="a.html" @submit.prevent="gotaobao">
<input type="submit" name="" @click.prevent="gotaobao">
</form>
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
gotaobao(){
console.log('gotaobao');
}
}
})
</script>
注意:默认事件有,a标签,表单事件等; 但是如果是表单可以使用当前方式,也可以使用 @submit.prevent
<div class="app">
<div class="warp" @click.capture="warp">外层div
<div class="inner" @click.stop="inner">内层div</div>
</div>
</div>
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
inner(){
console.log('inner');
},
warp(){
console.log('warp');
}
}
})
</script>
案例:在div中添加a标签,给a标签添加事件
<div class="app">
<div class="warp" @click="warp">外层div
<a href="http://www.baidu.com" @click.prevent.stop="inner">baidu</a>
</div>
</div>
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
inner(){
console.log('inner');
},
warp(){
console.log('warp');
}
}
})
</script>
vue运行为v-on在监听键盘事件时,添加了特殊的键盘修饰符 vue还非常贴心地给出了常用按键的别名,这样就不必去记keyCode
<!-- 数字:当按下13回车键,触发事件 -->
<input type="input" name="" @keydown.13="gotaobao">
<!-- 单词:当按下回车键,触发事件 -->
<input type="input" name="" @keydown.enter="gotaobao">
<input type="input" name="" v-on:keyup.left="gotaobao">
案例:模拟实现input的number效果
<input type="input" name="" @keydown.down="count -= 1" @keydown.up="count += 1" :value="count">
<!-- @keydown.38.prevent="num+=1" 阻止箭头向前移动 -->
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
}
})
</script>
常用的键别名:enter,tab,delete,esc,space,up,down,left,right
点击谁才会触发谁,冒泡和捕获都不存在
<div class="app">
<div class="inner" @click.self="gotaobao">
<input type="button" name="" value="按钮" @click="gotaobao">
</div>
</div>
<script>
let app = new Vue({
el:'.app',
data:{
count:0,
},
methods:{
gotaobao(event){
console.log(1111);
}
}
})
</script>
<!-- 给按钮添加点击事件,组织默认事件,并且只能执行一次 -->
<a href="http://www.baidu.com" @click.prevent.once="gotaobao">baidu</a>
总结:.self和.stop都有阻止冒泡的功能,那他们两个之间有什么区别呢? stop阻止所有的冒泡; self只阻止当前元素身上的冒泡行为;跟其他元素的冒泡没关系
<div id="app">
<input type="text" @keyup.13.38="change" v-model="msg">
</div>
<script>
methods: {
change(){
this.msg = '绿色'
}
}
</script>
案例3:指令练习-改变购买商品数量,总价会变化 需要知识点:键盘事件+点击事件+双向数据绑定
<table width="500" border="1" align="center" id="table">
<tr>
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>数量</td>
<td>总价</td>
</tr>
<tr>
<td>1</td>
<td>短袖</td>
<td>{{price}}</td>
<td>
<button @click="jian">-</button>
<!-- <input type="text" size="1" name="" id="" v-bind:value="num"> -->
<input type="text" @keyup.38.prevent="add" @keyup.40.prevent ='jian' size="1" name="" id="" v-model="num">
<!-- <input type="number" size="1" name="" id="" v-model="num"> -->
<button v-on:click="add">+</button>
</td>
<td>{{ num * price}}</td>
</tr>
</table>
</body>
<script>
let vm = new Vue({
el:'#table',
data:{
num:0,
price:53,
totlePrice:0,
},
methods:{
add(){
this.num++;
this.totlePrice = this.price*this.num
},
jian(){
if(this.num < 1 ){
this.num = 0
}else{
this.num--;
}
this.totlePrice = this.price*this.num
}
}
})
</script>
目标: 控制标签的隐藏或出现
<!--原理: display:none -->
<h1 v-show="isok">v-show的盒子</h1>
<!-- 从dom树删除该元素 -->
<h2 v-if="istrue">v-if的盒子</h2>
<!-- v-if v-else v-else-if -->
<p v-if="age < 18">未成年</p>
<p v-else-if="age > 18 && age < 60">成年</p>
<p v-else>老年</p>
<script>
var vm=new Vue({
el:'#app',
data:{
isok: false,
istrue: true,
age: 15,
}
})
</script>
条件渲染指令 v-if:如果表达式为真,则渲染该元素,如果为假,则不渲染(dom不存在) v-if和v-else之间不能有其它内容
<p v-if="count > 80">红色</p>
<p v-else-if="count > 60">蓝色</p>
<p v-else>绿色</p>
<script>
var vm=new Vue({
el:'#app',
data:{
count:70
},
})
</script>
注意:这里v-if,v-else要紧贴着使用,不然会报错,v-if显示,v-else就会隐藏。v-if隐藏,v-else就会显示 案例1:点击按钮切换登录/注册框
<div id="app">
<div v-if='show'>
<h1>登陆</h1>
用户名:<input type="text" /><br/>
密码:<input type="text" />
</div>
<div v-else>
<h1>注册</h1>
手机号:<input type="text" /><br/>
邮箱地址:<input type="text" />
</div>
<button @click='dianji'>切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: false
},
methods: {
dianji() {
this.show = !this.show
}
}
})
</script>
注意:当我们输入完内容之后,进行切换,会发现文字变化了,但是input没有变化 这是因为vuejs有一种尝试复用dom的机制,如果已经在的dom,会复用之前的dom,但是这并不是我们想要的效果,这个时候就可以给他加一个key值,告诉vuejs,这是唯一的,是不能复用的input
解决方案:只需要给所有的input添加一个key值就可以了
案例2:事件案例-切换登陆注册框
<style>
#app div{
border: 1px solid #f00;
width: 300px;
height: 300px;
}
</style>
<div id="app">
<div v-show="loginShow">
<h1>登陆</h1>
用户名:<input type="text" key="one" /><br/>
密码:<input type="text" key="two" />
</div>
<div v-show="registerShow">
<h1>注册</h1>
手机号:<input type="text" key="thr" /><br/>
邮箱地址:<input type="text" key="for" />
</div>
<button @click='change'>切换</button>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
show:true,
loginShow:true,
registerShow:false,
},
methods:{
change(){
this.loginShow = !this.loginShow;
this.registerShow = !this.registerShow;
}
}
})
</script>
条件渲染指令 v-show的效果跟v-if很相似,都有判断的效果,但是v-if是可以和v-else联合使用,但是v-show不可以,但是v-show,也可以判断 如果表达式为真,则显示该元素,如果为假,则隐藏该元素(dom存在)
<div id='app'>
<div v-show="flag1">
flag1的内容
</div>
<div v-show="flag2">
flag2的内容
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
flag1: true,
flag2: false,
}
})
</script>
注意:当v-if判断的时候不满足条件不现实,但是v-show不满足条件的时候添加了一个display:none的效果来隐藏
总结:v-show和v-if的区别
v-if 的特点:每次都会重新删除或创建元素 v-show的特点:每次不会重新进行dom的删除和创建操作,只是切换了元素的display:none样式 v-if 有较高的切换性能消耗 v-show 有较高的初始值渲染消耗 如果元素设计到频繁的切换,最好不要使用v-if,而是推荐使用v-show 如果元素kennel永远也不会被显示出来被用户看到,则推荐使用 v-if 自己总结: v-if: 判断是否加载,可以减轻服务器的压力,在需要时加载。 v-show:调整css dispaly属性,可以使客户端操作更加流畅。
列表渲染指令
<!-- 遍历数组: color: ['red','blue','green'] -->
<div id="app">
<ul>
<!-- item为数组中的每项元素-->
<li v-for="item in arr">{{item}}</li>
<!-- 等价于上面的效果 -->
<li v-for="item of arr">{{item}}</li>
<!-- item为元素值,index为索引; 括号中的顺序不能反 -->
<li v-for="(item,index) in arr">{{item}}----{{index}}</li>
</ul>
<ul>
<!-- 对象遍历 -->
<li v-for="(val,key,i) in person">{{val}}-{{key}}-{{i}}</li>
<li v-for="item in person">{{item}}</li> -->
<li v-for="(item,key) in person">{{key}}-----{{item}}</li>
<li v-for="(item,key,index) in person">{{index}}----{{key}}-----{{item}}</li>
</ul>
<!-- 数字遍历 -->
<div v-for="i in 10">{{i}}</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
arr: ['Amy', 'Rose', 'Black'],
person: {
name: 'Rose',
age: 34,
class: 'H5'
}
}
})
</script>
<div id="app">
<ul>
<li v-for="item in arr">{{item}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
arr: [23,14,56,34,78],
},
computed:{
items:function(){
return this.arr.sort((a,b)=>{
return a - b
})
}
}
})
</script>
<div id="app">
<ul>
<li v-for="(stu,index) in student">{{index+1}}---{{stu.name}}----{{stu.age}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
student:[
{name:'jack1',age:13},
{name:'jack2',age:48},
{name:'jack3',age:38},
{name:'jack4',age:18},
{name:'jack5',age:158}
]
},
computed:{
sortStu(){
return this.student.sort((a,b)=>{
return a.age - b.age
})
}
}
})
</script>
v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示:
<div id="app">
用户名:<input type="text" name="" id="" v-model="uname">
年龄:<input type="number" name="" id="" v-model="age">
<!-- 点击添加学生信息 -->
<button @click="add">添加</button>
<table width="400" border="1">
<tr>
<td></td>
<td>id</td>
<td>姓名</td>
<td>年龄</td>
</tr>
<!-- 遍历学生信息
必须添加key值,否则顺序会乱
注意:key值不能使用index,推荐使用数据中的id值
-->
<tr v-for="(per,index) in student" v-bind:key="per.name">
<td>
<input type="checkbox" name="" id="">
</td>
<td>{{index}}</td>
<td>{{per.name}}</td>
<td>{{per.age}}</td>
</tr>
</table>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
uname:'',
age:'',
student:[
{name:'rose',age:20},
{name:'jack',age:18},
{name:'Bob',age:21}
]
},
methods:{
add(){
this.student.unshift({name:this.uname,age:this.age});
}
}
})
</script>
当和 v-if 一起使用时,v-for 的优先级比 v-if 更高 这意味着 v-if 将分别重复运行于每个 v-for 循环中;但是这种优先机制,有时候也是非常有用的
<div id='app'>
<li v-for='val in arr' v-if='val%2==0'>
{{val}}
</li>
</div>
<script src='js/vue.js'></script>
<script>
var app = new Vue({
el: '#app',
data: {
arr: [1, 2, 3, 4, 5],
}
})
</script>
只有 v-model这唯一一个指令可以实现双向数据绑定 双向数据绑定 数据变化 -> 视图自动同步 视图变化 -> 数据自动同步 js数据
new Vue({
data: {
tel: '123'
}
})
模板
<p>请输入手机号:<input type="text" v-model="tel"></p>
<p>{{tel}}</p>
总结:使用v-model指令,可以实现表单元素和model中数据的双向绑定 注意:v-model只能运用在表单元素中input(text,address,email。。。),select,checked,textarea
<form @submit.prevent='formsub'>
<input type="text" v-model='oneform.username'>
<input type="text" v-model='oneform.password'>
<input type="submit" value="提价">
</form>
<script>
var app=new Vue({
el:'#app',
data:{
oneform: {
username: '',
password: '',
},
},
methods: {
formsub() {
console.log(this.oneform);
}
}
})
</script>
<form @submit.prevent='selSubmit'>
<select v-model='sel'>
<option value="">--请输入用户名--</option>
<option :value="{ city: 'beijing' }">北京</option>
<option :value="{ city: 'shanghai' }">上海</option>
<option :value="{ city: 'shenzhen' }">深圳</option>
</select>
<input type="submit" value="提交">
</form>
<script>
var app=new Vue({
el:'#app',
data:{
sel: '',
},
methods: {
selSubmit() {
console.log(this.sel);
console.log(this.sel.city);
},
}
})
</script>
注意:下拉菜单进行双休数据绑定的时候,需要让data和option中的value值保持一致
v-model.lazy 只有在input输入框发生一个blur时才触发 v-model.trim 将用户输入的前后的空格去掉 v-model.number 将用户输入的字符串转换成number
<div>
<!-- 输入内容转为字符串 -->
<input type="text" v-model.number='msg'>
<!-- 输入内容去除左右两边空格 -->
<input type="text" v-model:trim='msg'>
<!-- 输入内容的时候lazy不会改变,当失去焦点的时候才改变 -->
<input type="text" v-model.lazy='msg'>
<p>输出msg: {{msg}}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
msg: ''
}
})
</script>
eval() 解析执行某个字符串,并执行其中的的 JavaScript 代码。
<div id="app">
<input type="text" v-model='num1'/>
<select v-model='opt'>
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model='num2'/>
<input type="button" value="=" @click='cale'/>
<input type="text" v-model='result'/>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
num1:0,
num2:0,
result:0,
opt:'-'
},
methods:{
cale(){
switch(this.op){
case "+":
this.result = parseInt(this.num1)+parseInt(this.num2)
break;
case "-":
this.result = parseInt(this.num1)-parseInt(this.num2)
break;
case "*":
this.result = parseInt(this.num1)*parseInt(this.num2)
break;
case "/":
this.result = parseInt(this.num1)/parseInt(this.num2)
break;
}
/*
简单写法:不用转换数据类型
var codeStr=this.num1 + this.opt + this.num2;
this.result=eval(codeStr)
*/
}
}
})
</script>
v-once指令所在节点在初次动态渲染后,就视为静态内容了 以后数据改变不会引起v-once所在结构的更新,可以优化性能 只渲染一次
<!-- 单个元素 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 有子元素 -->
<div v-once>
<h1>comment</h1>
<p>{{msg}}</p>
</div>
<p>{{msg}}</p>
<p>{{msg}}</p>
<!-- 只渲染一次,数据更新,重新渲染页面时不会重新渲染该数据 -->
<p v-once>{{msg}}</p>
<p><button @click="change">修改msg的值</button></p>
<script>
data: {
msg:'hello'
},
methods: {
change() {
this.msg = '改变';
}
}
</script>
3. 实现购物车效果
4. 使用vue实现轮播图效果,点击下一页切换到下一张,点击上一页切换到上一张图片 5. 学生成绩录入、筛选、删除、监听 6. 实现tab切换效果
参考文档: