新手Vue3学习第3天

发布于:2022-12-16 ⋅ 阅读:(1320) ⋅ 点赞:(1)

2.模板与指令

2.1 模板语法

学习:插值表达式、js表达式、v-cloak

Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。

{{ number + 1 }}
​
{{ ok ? 'YES' : 'NO' }}
​
{{ message.split('').reverse().join('') }}
​
<div :id="`list-${id}`"></div>

在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。

2.1.1 文本插值

最基本的数据绑定形式是文本插值,它使用的是“Mustache[ˈmʌstæʃ]”语法 (即双大括号):

<span>Message: {{ msg }}</span>

双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。

2.1.2 js表达式

Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式:


 

这些表达式都会被作为 JavaScript ,以组件为作用域解析执行。

在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上:

  • 在文本插值中 (双大括号)

  • 在任何 Vue 指令 (以 v- 开头的特殊 attribute) attribute 的值中

绑定在表达式中的方法在组件每次更新时都会被重新调用,因此应该产生任何副作用,比如改变数据或触发异步操作。

2.1.3 v-cloak

用于隐藏尚未完成编译的 DOM 模板。

当使用直接在 DOM 中书写的模板时,可能会出现一种叫做“未编译模板闪现”的情况:用户可能先看到的是还没编译完成的双大括号标签,直到挂载的组件将它们替换为实际渲染的内容。

v-cloak 会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。配合像 [v-cloak] { display: none } 这样的 CSS 规则,它可以在组件编译完毕前隐藏原始模板。

[v-cloak] {
  display: none;
}
​
<div v-cloak>
  {{ message }}
</div>

直到编译完成前,<div> 将不可见。

完整案例:06_mustache.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>06_模板语法</title>
  <style>
    [v-cloak] {
      display: none;
    }
  </style>
</head>
<body>
  <!-- v-cloak -->
  <div id="app" v-cloak>
    <!-- 文本插值 -->
    <div>{{ msg }}</div>
    <!-- js表达式 -->
    <div>{{ number + 1 }}</div>
    <div>{{ flag ? 'ok': 'no' }}</div>
    <div>{{ message.split('').reverse().join('-') }}</div>
    <div v-bind:id="'list-' + id">111</div>
    <div v-bind:id=`list-${id}`>222</div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
​
  const { createApp } = Vue
  
  const app = createApp({
    data () {
      return {
        msg: 'hello vue',
        number: 100,
        flag: true,
        message: 'hello world',
        id: 100
      }
    }
  })
​
  app.mount('#app')
  
</script>
</html>

2.2 文本类指令

学习:v-text、v-html、v-pre

2.2.1 v-html & v-text

双大括号将会将数据插值为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令

<div v-html="rawHTML"></div>
 <div v-text="rawHTML"></div>
 <div>{{rawHTML}}</div>

在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容(script也属于HTML内容)。

2.2.2 v-pre

元素内具有 v-pre,所有 Vue 模板语法都会被保留并按原样渲染。最常见的用例就是显示原始双大括号标签及内容。

 <div v-pre>{{ rawHTML }}</div>

完整案例: 07_text.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>07_文本类指令</title>
</head>
<body>
  <div id="app">
    <!-- 解析输出 -->
    <div v-html="msg"></div>
    <!-- 转义输出 -->
    <div v-text="msg"></div>
    <!-- 文本插值 -->
    <div>{{ msg }}</div>
​
    <!-- v-pre 含有该指令的标签内部的语法不会被vue解析 -->
    <div v-pre>{{ msg }}</div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
​
  const { createApp } = Vue
  
  const app = createApp({
    data () {
      return {
        msg: '<h1>hello vue</h1>'
      }
    }
  })
​
  app.mount('#app')
  
</script>
</html>

2.3 属性绑定

学习:v-bind 以及简写形式

双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令

<div v-bind:id="myId"></div>

如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

因为 v-bind 非常常用,提供了特定的简写语法:

<div :id="myId"></div>

开头为 : 的 attribute 可能和一般的 HTML attribute 看起来不太一样,但它的确是合法的 attribute 名称字符,并且所有支持 Vue 的浏览器都能正确解析它。

布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。disabled 就是最常见的例子之一。

<button :disabled="flag">Button</button>

flag真值或一个空字符串 (即 <button disabled="">) 时,元素会包含这个 disabled attribute。而当其为其他假值时 attribute 将被忽略。

如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:

data () {
  return {
     obj: {
       a: 1,
       b: 2
     }
  }
}
<div v-bind="obj"></div>

完整案例: 08_attribute.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>08_绑定属性以及缩写形式</title>
</head>
<body>
  <div id="app">
    <!-- 如果属性的值是变量,boolean类型,number类型,对象,数组,null,undefined,需要使用绑定属性 -->
    <!-- 使用绑定属性遇到 null,undefined,则该属性自动不显示  -->
    <div v-bind:msg="msg" v-bind:flag="true" v-bind:num="100" v-bind:obj="{a: 1, b: 2}" v-bind:arr="['a', 'b']" v-bind:nu="null" v-bind:un="undefined"></div>
    <div :msg="msg" :flag="true" :num="100" :obj="{a: 1, b: 2}" :arr="['a', 'b']" :nu="null" :un="undefined"></div>
    <!-- 注意隐式类型转换,非空即为真,确保时 使用绑定属性 -->
    <button :disabled="false">按钮</button>
    <!-- 如果属性的值需要拼接字符串完成,且含有变量,可以使用 绑定属性结合 字符串拼接以及模板字符串 实现  -->
    <div v-bind:id="'list-' + id">111</div>
    <div v-bind:id=`list-${id}`>222</div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
​
  const { createApp } = Vue
  const app = createApp({
    data () {
      return {
        msg: 'hello vue',
        id: 100
      }
    }
  })
​
  app.mount('#app')
  
</script>
​
</html>

如果一个属性的值是变量,boolean类型,number类型,对象,数组,null,undefined,使用绑定属性

2.4 事件绑定

学习:v-on以及简写形式,methods应用

我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="methodName"@click="handler"

事件处理器的值可以是:

  1. 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。

  2. 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。

·内联事件处理器·通常用于简单场景,例如:

<button @click="count++">加 1</button>
<p>Count is: {{ count }}</p>

随着事件处理器的逻辑变得愈发复杂,内联代码方式变得不够灵活。因此 v-on 也可以接受一个方法名或对某个方法的调用。

方法事件处理器

<button @click="greet">问候</button>
 data () {
   return {
      name: 'Vue.js'
   }
 },
 methods: {
   greet(event) {
     // 方法中的 `this` 指向当前活跃的组件实例
     alert(`Hello ${this.name}!`)
     // `event` 是 DOM 原生事件
     if (event) {
       alert(event.target.tagName)
     }
  }
}

除了直接绑定方法名,你还可以在内联事件处理器中调用方法。这允许我们向方法传入自定义参数以代替原生事件:

methods: {
  say(message) {
    alert(message)
  }
}
<button @click="say('hello')">说 hello</button>
<button @click="say('bye')">说 bye</button>

内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数:

 <!-- 使用特殊的 $event 变量 -->
 <button @click="warn('表单不能提交.', $event)">提交</button>
 <!-- 使用内联箭头函数 -->
 <button @click="(event) => warn('表单不能提交.', event)">提交</button>
methods: {
  warn(message, event) {
    // 这里可以访问 DOM 原生事件
    if (event) {
      event.preventDefault()
    }
    alert(message)
  }
}

在处理事件时调用 event.preventDefault()event.stopPropagation() 是很常见的。尽管我们可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理 DOM 事件的细节会更好。

为解决这一问题,Vue 为 v-on 提供了事件修饰符

<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
​
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
​
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
​
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
​
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
​
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>
​
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
​
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
 <!-- 事件修饰符 -->
 <!-- 阻止冒泡-原生 -->
 <div class="parent" @click="clickParent1">
 <div class="child" @click="clickChild1"></div>
 </div>
 <!-- 阻止冒泡-事件修饰符 -->
 <div class="parent" @click="clickParent2">
 <div class="child" @click.stop="clickChild2"></div>
 </div>
methods: {
    clickParent1 (event) {
    console.log('parent1')
    },
    clickChild1 (event) {
    event.stopPropagation()
    console.log('child1')
    },
    clickParent2 (event) {
    console.log('parent2')
    },
    clickChild2 (event) {
    console.log('child2')
    },
}
.parent {
    width: 200px;
    height: 200px;
    background: #f66;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 10px;
}
.child {
    width: 100px;
    height: 100px;
    border: 1px solid #ccc;
}

在监听键盘事件时,我们经常需要检查特定的按键。Vue 允许在 v-on@ 监听按键事件时添加按键修饰符

<!-- 按键修饰符 -->
 <!-- 原生 -->
 <input type="text" @keyup="print1">
 <!-- vue -->
 <input type="text" @keyup.enter="print2">
methods: {
    print1 (event) {
        if (event.keyCode === 13) {
            console.log('打印1')
        }
    },
    print2 () {
        console.log('打印2')
    }
}
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right

你可以使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发

.ctrl
.alt
.shift
.meta
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>

完整案例: 09_event.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>09_绑定事件</title>
  <style>
    .parent {
      width: 200px;
      height: 200px;
      background-color: #f66;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .child {
      width: 100px;
      height: 100px;
      background-color: #ccc;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- 内联事件处理器 -->
    <button v-on:click="count++">加1</button> {{ count }}<br />
    <!-- 方法事件处理器 -->
    <button v-on:click="add">加1</button> {{ count }}<br />
​
    <button @click="say('hello', $event)">say hello</button>
    <button @click="say('bye', $event)">say bye</button>
​
    <!-- 事件对象 - 阻止事件冒泡,阻止默认事件 -->
    <form @submit="getUserInfo">
      <input type="text" name="userName" placeholder="用户名" />
      <input type="password" name="password" placeholder="密码" />
      <input type="submit" value="提交">
    </form>
    <div class="parent" @click="print('parent', $event)">
      <div class="child" @click="print('child', $event)"></div>
    </div>
​
    <!-- 事件修饰符 - 阻止事件冒泡,阻止默认事件  -->
    <form @submit.prevent="getUserInfoVue">
      <input type="text" name="userName" placeholder="用户名" />
      <input type="password" name="password" placeholder="密码" />
      <input type="submit" value="提交">
    </form>
    <div class="parent" @click="printVue('parent')">
      <div class="child" @click.stop="printVue('child')"></div>
    </div>
​
    <!-- 事件对象 -  回车时打印数据 -->
    <input type="text" @keyup="printData" />
    <!-- 按键修饰符 -  回车时打印数据 -->
    <input type="text" @keyup.enter="printDataVue" />
    <!-- vue2中可以 根据 keyCode 作为修饰符, vue3中不支持 -->
    <input type="text" @keyup.13="printDataVueCode" />
​
    <!-- 使用系统修饰符可以自定义组合按键 -->
    <!-- 用户点击 alt 加 enter时 清空输入框数据 -->
    <!-- v-model 属于表单的输入绑定 -->
    <input type="text" v-model="text" @keyup.alt.enter="clear"/> {{ text }}
    <div @click.ctrl="doSomething">Do something</div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
​
  const { createApp } = Vue
  const app = createApp({
    data () {
      return {
        count: 10,
        name: 'Vue.js',
        text: '1'
      }
    },
    methods: { // 所有自定义的vue的事件都应该写在 methods 中
      // 如果使用事件时,没有添加(),那么事件含有默认参数为 event
      add (event) {
        // this其实就是vue的实例
        // this.count++
        // this.count += 1
        this.count = this.count + 1
        console.log(this.name)
        console.log(event) // PointerEvent 与原生js中的事件对象保持一致(react中使用的不是原生js的事件对象)
      },
      // 如果使用事件时添加(),并且还想用事件对象,那么传递事件对象的vue的专属参数 $event
      say (msg, event) {
        console.log(msg, event)
      },
      getUserInfo (event) {
        event.preventDefault()
      },
      getUserInfoVue () {
​
      },
      print (msg, event) {
        event.stopPropagation()
        console.log(msg)
      },
      printVue (msg) {
        console.log(msg)
      },
      printData (event) {
        if (event.keyCode === 13) {
          console.log('1')
        }
      },
      printDataVue () {
        console.log(2)
      },
      printDataVueCode () {
        console.log(3)
      },
      clear () {
        this.text = ''
      },
      doSomething () {
        console.log('doSomething')
      }
    }
  })
​
  app.mount('#app')
  
</script>
​
</html>

2.5条件渲染

学习:v-if、v-else-if、v-else、v-show

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。

也可以使用 v-elsev-if 添加一个“else 区块”

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

<div v-if="grade >= 90">优</div>
<div v-else-if="grad" >= 80">良</div>
<div v-else-if="grade >= 70">中</div>
<div v-else-if="grade >= 60">差</div>
<div v-else>不及格</div>
data () {
    return {
        grade: 66
    }
}

v-elsev-else-if 也可以在 <template> 上使用。

想要切换不止一个元素,在这种情况下我们可以在一个 <template> 元素上使用 v-if,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个 <template> 元素。---- tempalte是一个空标签

另一个可以用来按条件显示一个元素的指令是 v-show。其用法基本一样:

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

<!-- v-show -->
<div v-show="grade >= 90 && grade < 100">优</div>
<div v-show="grade >= 80 && grade < 90">良</div>
<div v-show="grade >= 70 && grade < 80">中</div>
<div v-show="grade >= 60 && grade < 70">差</div>
<div v-show="grade < 60">不及格</div>

完整案例:10_condition.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>10_条件渲染</title>
</head>
<body>
  <div id="app">
    <button @click="grade++"> 加</button> {{ grade }}<button @click="grade--">减</button>
    <!-- v-if v-else-if v-else -->
    <div v-if="grade >=90">优</div>
    <div v-else-if="grade >=80">良</div>
    <div v-else-if="grade >=70">中</div>
    <div v-else-if="grade >=60">差</div>
    <div v-else>不及格</div>
​
    <hr />
    <!-- v-show -->
    <div v-show="grade >= 90">优</div>
    <div v-show="grade >= 80 && grade < 90">良</div>
    <div v-show="grade >= 70 && grade < 80">中</div>
    <div v-show="grade >= 60 && grade < 70">差</div>
    <div v-show="grade < 60">不及格</div>
​
    <!-- 假如不同条件下需要同时控制多个元素的显示和不显示 -->
    <div v-if="flag">1</div>
    <div v-if="flag">2</div>
    <div v-if="flag">3</div>
    <!-- template 属于vue框架中的空标签,审查元素时不会被渲染出来 -->
    <template v-if="flag">
      <div>4</div>
      <div>5</div>
      <div>6</div>
    </template>
​
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
​
  const { createApp } = Vue
  const app = createApp({
    data () {
      return {
        grade: 61,
        flag: true
      }
    }
  })
​
  app.mount('#app')
  
</script>
​
</html>

v-if vs v-show

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

2.6列表渲染

学习:v-for 以及key属性

我们可以使用 v-for 指令基于一个数组(对象、字符串)来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名

data() {
  return {
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
​
<li v-for="item in items">
  {{ item.message }}
</li>

v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。

data() {
  return {
    parentMessage: 'Parent',
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
​
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>

列表渲染需要添加key值,对于多层嵌套的 v-for,作用域的工作方式和函数的作用域很类似

完整案例: 11_list.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>11_列表渲染</title>
</head>
<body>
  <div id="app">
    <!-- 列表渲染中的 key 需要使用列表数据的唯一值
      实在不得已情况下,可以使用 数组 的索引值作为key值
      v-for="(item, index) of list" :key="index"
    --4>
    <!-- 没有key -->
    <ul>
      <li v-for="item of arr">
        {{ item }}
      </li>
    </ul>
    <button @click="beforeArrAdd">arr前追加数据</button>
    <button @click="afterArrAdd">arr后追加数据</button>
    <!-- 添加key -->
    <ul>
      <li v-for="item of arr" :key="item">
        {{ item }}
      </li>
    </ul>
    <ul>
      <li v-for="item of items">
        {{ item.message }}
      </li>
    </ul>
    <button @click="getData">获取数据</button>
    <ul>
      <li v-for="item of list" :key="item.proid">
        {{ item.proname }}
      </li>
    </ul>
    <ul>
      <li v-for="item of carList">
        <div>{{ item.brand }}</div>
        <ol>
          <li v-for="itm in item.list">
            {{ itm }}
          </li>
        </ol>
      </li>
    </ul>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script src="lib/jquery.js"></script>
<script>
​
  const { createApp } = Vue
  const app = createApp({
    data () {
      return {
        arr: ['a', 'b', 'c', 'd'],
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ],
        list: [],
        carList: [
          {
            brand: '宝马',
            list: ['X5', 'X6']
          },
          {
            brand: '雷克萨斯',
            list: ['XT5', 'AT6']
          }
        ]
      }
    },
    methods: {
      getData () {
        // http://121.89.205.189:3001/apidoc/#api-Pro-GetProList
        // 原生js ajax
        // jQuery ajax --- 不要再vue以及react中使用jQuery,因为 jQuery 大量的api都是基于DOM的
        // $.ajax({
        //   url: 'http://121.89.205.189:3001/api/pro/list',
        //   method: 'GET',
        //   success: res => { // ? 为什么要使用 箭头函数
        //     console.log(res)
        //     this.list = res.data
        //   }
        // })
        // fetch -- 需要先转换为 json 的格式,再使用
        fetch('http://121.89.205.189:3001/api/pro/list').then(res => res.json()).then(res=> {
          console.log(res)
          this.list = res.data
        })
      }
    },
    methods: {
      beforeArrAdd () {
        this.arr.unshift('e')
      },
      afterArrAdd () {
        this.arr.push('f')
      }
    }
  })
​
  app.mount('#app')
  
</script>
​
</html>

v-if 与 v-for 同时存在于一个元素上,会发生什么?

12_vue3_if_for.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>12_vue3的v-if与v-for优先级</title>
</head>
<body>
<div id="app">
 <ul>
   <li v-for="(item, index) of arr" :key="index" v-if="flag">
     {{ item }}
   </li>
 </ul>
</div>
</body>
<script src="lib/vue.global.js"></script>
<script>
Vue.createApp({
 data () {
   return {
     arr: ['a', 'b', 'c', 'd'],
     flag: false
   }
 }
}).mount('#app')
</script>
</html>

13_vue2_if_for.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>13_vue2的v-if与v-for优先级</title>
</head>
<body>
<div id="app">
 <ul>
   <li v-for="(item, index) of arr" :key="index" v-if="flag">
     {{ item }}
   </li>
 </ul>
</div>
</body>
<script src="lib/vue.js"></script>
<script>
new Vue({
 data: {
   arr: ['a', 'b', 'c', 'd'],
   flag: false
 }
}).$mount('#app')
​
</script>
</html>

通过审查元素得知:

vue3中,v-if的优先级高于v-for

vue2中,v-for的优先级高于v-if

2.7 表单输入绑定

学习:v-model

在前端处理表单时,我们常常需要将表单输入框的内容同步给 JavaScript 中相应的变量

<input
  :value="text"
  @input="event => text = event.target.value">

v-model 指令帮我们简化了这一步骤:

<input v-model="text">

v-model 还可以用于各种不同类型的输入,<textarea><select> 元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:

  • 文本类型的 <input><textarea> 元素会绑定 value property 并侦听 input 事件;

  • <input type="checkbox"><input type="radio"> 会绑定 checked property 并侦听 change 事件;

  • <select> 会绑定 value property 并侦听 change 事件

v-model 会忽略任何表单元素上初始的 valuecheckedselected attribute。它将始终将当前绑定的 JavaScript 状态视为数据的正确来源。你应该在 JavaScript 中使用data 选项来声明该初始值。

完整案例: 14_model.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>14_表单输入绑定</title>
</head>
<body>
  <div id="app">
    <div>
      用户名: <input type="text" v-model="userName" /> {{ userName }}
    </div>
    <div>
      密  码: <input type="password" v-model="password" /> {{ password }}
    </div>
    <div>
      性  别: <input type="radio" name="sex" v-model="sex" value="男"/>男<input type="radio" name="sex" v-model="sex" value="女"/>女 --- {{ sex }}
    </div>
    <div>
      阶  段: <select v-model="lesson">
        <option :value="1">一阶段</option>
        <option :value="2">二阶段</option>
        <option :value="3">三阶段</option>
      </select> ---- {{ lesson === 1 ? '一阶段' : lesson === 2 ? '二阶段' : '三阶段' }}
    </div>
    <div>
      爱  好:
      <input type="checkbox" name="hobby" value="🏀" v-model="hobby"/>🏀
      <input type="checkbox" name="hobby" value="⚽" v-model="hobby"/>⚽
      <input type="checkbox" name="hobby" value="🏓" v-model="hobby"/>🏓
      <input type="checkbox" name="hobby" value="⚾" v-model="hobby"/>⚾
      <input type="checkbox" name="hobby" value="🌏" v-model="hobby"/>🌏
    </div> ---- {{ hobby }}
    <div>
      备  注: <textarea v-model="note"></textarea> {{ note }}
    </div>
    <div>
      <input type="checkbox" v-model="flag"/> 同意*******协议 --- {{ flag }}
    </div>
    <div>
      <input type="button" value="提交" @click="submit" /> 
    </div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
  Vue.createApp({
    data () {
      return {
        userName: '',
        password: '',
        sex: '男',
        lesson: 1,
        note: '',
        hobby: ['🌏'], // 表示多选-数组
        flag: false // 表示开关 - boolean
      }
    },
    methods: {
      submit () {
        if (this.flag) {
          console.log({
            userName: this.userName,
            password: this.password,
            sex: this.sex,
            hobby: this.hobby,
            lesson: this.lesson,
            note: this.note
          })
        } else {
          alert('请先勾选用户协议')
        }
      }
    }
  }).mount('#app')
</script>
</html>

2.8 类与样式绑定

数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 classstyle 都是 attribute,我们可以和其他 attribute 一样使用 v-bind 将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,Vue 专门为 classstylev-bind 用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。

不管是类class还是样式style,都有对象和数组的写法

完整案例: 15_style.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>15_类与样式绑定</title>
  <style>
    .a {
      font-size: 30px;
    }
    .b {
      color: #f66;
    }
  </style>
</head>
<body>
  <div id="app">
    <input type="checkbox" v-model="flag" />
    <div class="a b">群组选择器</div>
    <!-- 在flag字段为真时,才显示红色的30px的字体 -->
    <!-- class对象写法,key为定义的样式,value为条件 -->
    <div :class="{ a: flag, b: flag }">class的对象写法</div>
    <!-- class数组写法 -->
    <div :class="[{a: flag}, {b: flag}]">class数组写法</div>
    <!-- 三元运算符 -->
    <div :class="flag ? 'a b' : ''">三元运算符 class写法</div>
​
    <!-- style对象写法,小驼峰式以及短横线连接方式  -->
    <div :style="{ color: color, fontSize: fontSize }">style对象写法</div>
    <!-- style数组写法 -->
    <div :style="[{color: color}, {fontSize: fontSize}]">style数组写法</div>
  </div>
</body>
<script src="lib/vue.global.js"></script>
<script>
  Vue.createApp({
    data () {
      return {
        flag: false,
        color: '#00f',
        fontSize: '50px'
      }
    }
  }).mount('#app')
</script>
</html>

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到