03Vue3-模板语法

17 篇文章 6 订阅
本文详细介绍了Vue.js的模板语法,包括插值操作、计算属性、事件监听、条件渲染、列表渲染以及v-model的使用。内容涵盖数据绑定、计算属性的缓存功能、事件修饰符、条件分支、列表遍历、双向数据绑定以及简易购物车的实现。文章深入浅出地解析了Vue.js中这些核心概念,并提供了丰富的示例代码。
摘要由CSDN通过智能技术生成

模板语法

1. 插值操作

  1. 插值:{{}}
    双大括号里支持表达式,如:

{{ number + 1 }} {{ ok ? ‘YES’ : ‘NO’ }} {{
message.split(’’).reverse().join(’’)}}

  1. 指令:v-
    (在{{}}和v-指令进行数据绑定时,支持js单个表达式)
    <p v-once>{{msg}}</p> 数据执行一次性插值,数据改变时,插值处内容不更新,不响应
    <p v-pre>{{msg}}</p>,内容原封不动的展示
    <p v-text='msg'></p>,就相当于插值表达式的功能
    <p v-html='title'></p>,可以输出html代码
    data:{
    msg:‘test message’,
    title:<h1 style='color:red'>Title</h1>
    }

  2. v-bind
    插值{{}}只能用在模板内容中,用于动态内容绑定
    如果希望元素的属性也可以动态绑定,需要通过v-bind指令

<!-- 完整语法 -->
<a v-bind:href="url"> ... </a>

<!-- 缩写 -->
<a :href="url"> ... </a>

<!-- 动态参数的缩写 -->
<a :[key]="url"> ... </a>
  • 绑定有意义元素中的属性
<template>
<h2 title="this is a test">{{msg}}</h2>

<h2 v-bind:title="msg">{{msg}}</h2>
<!--等价于 -->
<h2 :title="info">{{info}}</h2>

<img :src="imgsrc" width="100" height="100" alt="">
<a :href="url">百度</a>
</template>
 
<script>
const data = {
    msg: 'this is a test',
    info: 'new info',
    imgsrc: 'https://v3.vuejs.org/logo.png',
    title: '<h1 style="color: red">Title</h1>',
    url: 'http://www.baidu.com'
}
export default {
  name: 'App',
  data() {
    return data
  }
}
</script>

  • 绑定class属性,四种用法(字符串,数组,对象,方法)
<template>
<!-- 数组方法 -->
<div :class="[one,two]">box4</div>
<!-- 等价于(字符串用法) -->
<div :class="active">box5</div>

<!-- 对象方法(常用) -->
<!-- isOne和isTwo为布尔值,真则加该类(one/two),假则不加-->
<div :class="{one:isOne, two:isTwo}">box6</div>

<!-- 若键值对相同,则简写一个即可 -->
<div :class="{demo:demo}">box6</div> 
<!-- 等价于 -->
<div :class="{demo}">box6</div> 

<!-- 若样式太多,可采用方法 -->
<div :class="getStyleArr()">box7</div>
<div :class="getStyleObject()">box8</div>
</template>

<script>
const data = {
    one: 'one',
    two: 'two',
    active: ['one','two'],
    isOne: true,
    isTwo: false,
    demo: true
}
export default {
  name: 'App',
  data() {
    return data
  },
  methods() {
    getStyleArr() {
      return [this.one,this.two];
    },
    getStyleObject() {
      return {
        one: this.isOne,
        two: this.isTwo
      }
}
</script>
<style scoped>
.one {
  background-color: rebeccapurple;
  font-weight: bold;
}
.two {
  background-color: #42b983;
}
.demo {
  background-color: #333;
}
</style>
  • 绑定style属性
    有种方法,一种数组语法、一种是对象语法
<template>
<!-- 数组方法-->
<div :style="['font-size:100px','background:red']">box1</div>
<!-- 等价于 -->
<div :style="[fontSize, bgColor]">box2</div>
<div :style="['font-size:'+size+'px','background:'+color]">box3</div>

<!-- 对象方法-->
<div :style="{fontSize: '15px', 'background-color':'yellow'}">box9</div>
<div :style="{'font-size': '15px', 'background-color':'yellow'}">box9</div>
</template>

<script>
const data = {
    fontSize: 'font-size:50px',
    bgColor: 'background-color:green',
    size: 90,
    color: 'yellow'
}
export default {
  name: 'App',
  data() {
    return data
  }
</script>

2. 计算属性

computed计算属性有缓存的功能,计算属性在处理一些复杂逻辑时是很有用的。

<template>
<div>
    <h3>{{name}} - {{slogen}}</h3>
    <h3>{{name +' - ' + slogen}}</h3>
    <h3>{{getTitle()}}</h3>
    <h3>{{title}}</h3>
</div>
</template>

<script>
const data = {
    name: '张三',
    slogen: '新的世界'
}
export default {
  name: 'App',
  data() {
    return data
  },
  computed: {
    title: {
      get() {
        console.log('get computed')
        return this.name+ ' - '+this.slogen;
      }
    }
  },
  methods: {
    getTitle() {
      console.log('get methods')
      return this.name+ ' - '+this.slogen;
    }
  }
}
</script>

在这里插入图片描述

methods和computed两者有什么区别呢?
如果有多个数据

    <h3>{{getTitle()}}</h3>
    <h3>{{getTitle()}}</h3>
    <h3>{{getTitle()}}</h3>
    <h3>{{title}}</h3>
    <h3>{{title}}</h3>
    <h3>{{title}}</h3>

运行查看控制台
在这里插入图片描述

methods里的getTitle()是使用多少次方法就调用多少次。
而computed有缓存的作用,只计算一次,computed里的title依赖于name和sologen,只要name和slogen没有变化,这个两个属性值就一直保存在缓存中,若更改,则相应title绑定也会更新。

计算属性默认只有getter,需要时也提供一个setter

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...
总价:<small></small>{{totalPrice}}
.....
const data = {
    books: [
      {id:1, name:'JS大红本第一版',price:120},
      {id:1, name:'JS大红本第二版',price:130},
      {id:1, name:'JS大红本第三版',price:150},
      {id:1, name:'JS大红本第四版',price:190}
    ]
}
export default {
  name: 'App',
  data() {
    return data
  },
	//计算属性
  computed: {
    totalPrice: {
      get() {
        //汇合
        return this.books.reduce((s,n)=> s+=n.price, 0)
      }
    }
  }
}

在这里插入图片描述

3. 事件监听

在前端开发中,需要经常和用户交互
绑定事件监听器指令:v-on
缩写: @ (语法糖)
参数: $event (获取事件对象)
v-on事件修饰符号

  • .stop阻止事件冒泡
  • .self 当事件在该元素本身触发时才触发事件
  • .capture 添加事件侦听器是,使用事件捕获模式
  • .prevent 阻止默认事件
  • .once 事件只触发一次
  • .enter 只有在 keyEnter 时调用
  • 修饰符可串联
    <a @click.stop.prevent="doThat"></a>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

<
!-- 完整语法 -->
<a v-on:click="doSomething"> ... </a>

<!-- 缩写 -->
<a @click="doSomething"> ... </a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
<template>
  <div>
    msg = {{msg}}<br>
    <input type="text" v-model="msg"><br><br>
    num = {{num}}<br>
    //<button @click="num--">-</button>
    <button @click="sub">-</button>
    <input type="text" size="3" v-model="num">
    //<button @click="num++">+</button>
    <button @click="add">+</button>
  </div>
</template>

<script>
const data = {
    msg: 'this is a test',
    num: 0,
    max: 10,
    min: 0
}
export default {
  name: 'App',
  data() {
    return data
  },
  methods: {
    add() {
      if (this.num >= this.max) {
        this.num = this.max;
      } else {
        this.num++;
      }

    },
    sub() {
      if (this.num <= this.min) {
        this.num = this.min;
      }else {
        this.num--;
      }
    }
  }
}
</script>

<style>
.....
</style>

效果
在这里插入图片描述
获取事件对象

<button @click="sub('sub',$event)">-</button>
<input type="text" size="3" v-model="num">
<button @click="add">+</button>
 add(e) {
      console.log(e);          //没传参,获取得到事件对象
      if (this.num >= this.max) {
        this.num = this.max;
      } else {
        this.num++;
 }

},
sub(p) {
	 console.log(p,e);          //传参了,一个为’sub',一个为事件对象
	 if (this.num <= this.min) {
	   this.num = this.min;
	 }else {
	   this.num--;
	 }
 }

在这里插入图片描述

<div @click="one()" class="box1">
    <div @click="two()" class="box2">
      <button @click="three()">按钮</button>
    </div>
</div>

<script>
.....
export default {
  name: 'App',
  data() {
    return data
  },
  methods: {
    one() {
      console.log('one');
    },
    two() {
      console.log('two');
    },
    three() {
      console.log('three');
    }

  }
}
</script>
<style scoped>
.box1 {
  width: 150px;
  height: 150px;
  background-color: #42b983;
}
.box2 {
  width: 100px;
  height: 100px;
  background-color: rebeccapurple;
}
</style>

在这里插入图片描述在这里插入图片描述
点击按钮,事件冒泡
若要停止事件冒泡,则<button @click.stop="three()">按钮</button>
可串行使用

<div @click.self.stop="two()" class="box2">
   <button @click="three()">按钮</button>
</div>

4. 条件渲染

v-ifv-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染并保留在 DOM 中,并且只是简单地基于 CSS 进行切换(display)

v-if有更高的切换开销,而v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show较好;如果在运行时条件很少改变,则使用 v-if 较好。

条件分支 v-if v-else
多条件分支 v-if v-else-if v-else

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

<!-- awesome: true/false -->
<button @click="isShow = !isShow">显示/隐藏</button>
<h1 v-if="isShow">Vue is awesome!</h1>
<h1 v-show="isShow">Oh no 😢</h1>
<!-- isShow: true/false -->

显示状态
在这里插入图片描述

隐藏状态
在这里插入图片描述

5. 列表渲染

遍历指令:v-for
遍历数组 v-for=”(item, [index]) in 数组”
遍历对象 v-for=”(value, [key], [index]) in 对象”
vue中列表循环需加:key="唯一标识" 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM,使用diff算法的处理方法,对操作前后的dom树同一层的节点进行对比,一层一层对比

<div id="app">
	<ul>
      <p>遍历数组</p>
      <li v-for="(item,index) in list" :key="item">{{ index+1}} - {{ item }}</li>
    </ul>
    <ul>
      <p>遍历对象</p>
      <li v-for="(item,key,index) in obj" :key="item">{{index+1}} - {{ key}} - {{ item }}</li>
    </ul>
    <ul>
      <p>遍历数组对象</p>
      <li v-for="(item,index) in books" :key="item.id">{{ index+1 }} - {{ item.name }} - {{item.price}}</li>
    </ul>
    
</div>
Vue.createApp({
  data() {
    return {
      list: ['Java','Python','C/C++','PHP','Vue'],
      obj: {
	    name: '百度',
	    url: 'http://www.baidu.com',
	    slogen: 'get it'
	  },
	 books: [
	    {id:1, name:'Foo',price:20},
	    {id:2, name:'Bar',price:25},
	    {id:3, name:'Zun',price:50},
	    {id:4, name:'Dom',price:40},
	  ]
    }
  }
}).mount('#app')

在这里插入图片描述
选中样式应用

<div id="app">
    <ul>
      <p>遍历数组对象</p>
     <li :class="{active:item.active}" @mouseenter="over(index)" v-for="(item,index) in books" :key="item.id">{{ index+1 }} - {{ item.name }} - {{item.price}}</li> 
    </ul>
    
</div>
Vue.createApp({
  data() {
    return {
      books: [
	   {id:1, name:'Foo',price:20, active: false},
	    {id:2, name:'Bar',price:25, active: false},
	    {id:3, name:'Zun',price:50, active: false},
	    {id:4, name:'Dom',price:40, active: false},
	  ]
    }
  },
  methods: {
    over(index) {
      for (let i in this.books) {
        if (index == i)
          this.books[index].active = true;
        else
          this.books[i].active = false;
      }
   }
}).mount('#app')
<style scoped>
ul li {
  list-style: none;
}
.active {
  background-color: antiquewhite;
  color: coral;
}
</style>

在这里插入图片描述

6. v-model

v-model指令的本质是: 它负责监听用户的输入事件,从而更新数据,并对一些极端场景进行一些特殊处理。同时,v-model会忽略所有表单元素的value、checked、selected特性的初始值,它总是将vue实例中的数据作为数据来源。 然后当输入事件发生时,实时更新vue实例中的数据。

实现原理:
<input v-bind:value="message" v-on:input="message = $event.target.value" />
v-model的修饰符号:

  • .lazy懒加载修饰符
  • .number 修饰符让其转换为 number 类型
  • ·.trim修饰符可以自动过滤掉输入框的首尾空格

v-model 组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。 v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
  1. v-bind绑定一个value属性
  2. v-on指令给当前元素绑定input事件

自定义组件使用v-model,有以下操作:
1. 接收一个value prop
2. 触发input事件,并传入新值

在原生表单元素中 c <input v-model="parentData">

等价于 <input v-bind:value="parentData" v-on:input="parentData = $event.target.value"> 简写 <input :value="parentData" @input= "parentData = $event.target.value">

@input是对输入事件的一个监听,:value="parentData"是将监听事件中的数据放入到input。

在自定义组件中

c my-component v-model="inputValue"></my-component> 等价于 <my-component v-bind:value="inputValue" v-on:input="inputValue = argument[0]"> </my-component> 这个时候,inputValue接受的值就是input事件的回调函数的第一个参数,所以在自定义组件中,要实现数据绑定,还需要$emit去触发input的事件。

this.$emit('input', value)

v-model不仅可以给input赋值还可以获取input中的数据,而且数据的获取是实时的,因为语法糖中是用@input对输入框进行监听的。

  1. 输入框
      
    双向绑定
<input type="text" v-model="msg"><br>
    {{msg}}

在这里插入图片描述

单向绑定

<input type="text" :value="msg"><br>
    {{msg}}

<!-- 双向绑定 -->
<input type="text" :value="msg" @input="msg=$event.target.value"><br>
    {{msg}}

在这里插入图片描述

  1. 单选框
<label for="one">
   <input type="radio" id="one" value="" v-model="sex"></label>
 <label for="two">
   <input type="radio" id="two" value="" v-model="sex"></label>
 <br> sex: {{sex}}
Vue.createApp({
  data() {
    return {
      sex: '男'
    }
  }
}).mount("#app")

在这里插入图片描述

  1. 复选框
    单个复选框
<input type="checkbox" v-model="checked" id="checkbox">
<label for="checkbox">{{checked}}</label>
Vue.createApp({
  data() {
    return {
      checked: false
    }
  }
}).mount("#app")

在这里插入图片描述在这里插入图片描述

多个复选框

<div id="app">
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames" />
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
  <label for="mike">Mike</label>
  <br />
  <span>Checked names: {{ checkedNames }}</span>
</div>
Vue.createApp({
  data() {
    return {
      checkedNames: []
    }
  }
}).mount("#app")

在这里插入图片描述

  1. 选择框
<div id="app">
  <select v-model="selected">
      <option disabled value="">Please select one</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
Vue.createApp({
  data() {
    return {
      selected : ''
    }
  }
}).mount("#app")

在这里插入图片描述

选择框多选时

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
<br />
<span>Selected: {{ selected }}</span>

在这里插入图片描述
v-for渲染的动态选项

<div id="app">
  <select v-model="selected">
     <option v-for="op in options" :value="op.value" :key="op.value">{{op.name}}</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
Vue.createApp({
  data() {
    return {
      selected: 'zs',
	  options: [
	    {name:'张三',value:'zs'},
	    {name:'王五',value:'ww'},
	    {name:'李四',value:'ls'},
	    {name:'梅芳',value:'mf'},
	  ]	
    }
  }
}).mount("#app")

在这里插入图片描述

模板语法应用——简易购物车

<template>
  <div>
    <div v-if="cartlist.length <= 0">您没有选择的商品,购物车为空,<a href="#">去购物</a></div>
    <table v-else>
      <caption><h1>购物车</h1></caption>
      <tr>
        <th></th>
        <th>编号</th>
        <th>商品名称</th>
        <th>商品价格</th>
        <th>购买数量</th>
        <th>操作</th>
      </tr>
      <tr v-for="(item,index) in cartlist" :key="item.id">
        <td><input type="checkbox" v-model="item.checked"></td>
        <td>{{item.id}}</td>
        <td>{{item.name}}</td>
        <td><small></small>{{item.price.toFixed(2)}}</td>
        <td>
          <button @click="item.count--" :disabled="item.count <= 1 ">-</button>
          {{ item.count}}
          <button @click="item.count++">+</button>
        </td>
        <td><a href="#" @click.prevent="del(index)">删除</a></td>
      </tr>
      <tr>
        <td colspan="3" align="right">总价</td>
        <td colspan="3">{{ totalPrice }}</td>
      </tr>
    </table>
  </div>

</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      cartlist: [
        {id:1, checked:true, name:'《活着》', price:80, count:1},
        {id:2, checked:true, name:'《岛上世界》', price:40, count:1},
        {id:3, checked:true, name:'《权力属于有自制力的人》', price:50, count:1},
        {id:4, checked:true, name:'《朝花夕拾》', price:120, count:1},
        {id:5, checked:true, name:'《完美世界》', price:99, count:1},
        {id:6, checked:true, name:'《无间道》', price:39, count:1},
      ]
    }
  },
  computed: {
    totalPrice: {
      get() {
        let sum = 0;
        for (let book of this.cartlist) {
          if (book.checked)
            sum += book.count * book.price;
        }
        return '¥'+sum.toFixed(2);
      }
    }
  },
  methods: {
    del(index) {
          this.cartlist.splice(index,1)
      }
    }
}
</script>

<style scoped>
table {
  width: 600px;
  border: 1px solid #333;
  border-collapse: collapse;
}
th {
  background-color: #d2d2d2;
}
td, th {
  bord`在这里插入代码片`er: 1px solid #333333;
  padding: 10px;
}
</style>

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值