Vue基础语法


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>Vue中应⽤和组件的概念</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      // createApp 表示创建⼀个 Vue 应⽤ ,存储到 app 变量中
      // 传⼊的参数表示,这个应⽤最外层的组件,应该如何展示
      // mvvm设计模式:m -> model数据,v ->view 视图 ,vm -> viewModel 视图数据连接层
      const app = Vue.createApp({
        data() {
          return {
            message: "hello world",
          };
        },
        template: `<h2>{{message}}</h2>`,
      });
      // vm 代表的就是 Vue 应⽤的根组件,mount返回的根组件
      const vm = app.mount("#app");
    </script>
  </body>
</html>

可以操作 vm

  1. createApp 表示创建⼀个 Vue 应⽤,存储到 app 变量中

  2. 传⼊的参数表示,这个应⽤最外层的组件,应该如何展示

  3. mvvm 设计模式

    a. m->model 数据 data()

    b. v->view 视图 template:

    c. vm->viewModel 视图数据连接层 ( Vue 组件实现)

const vm = app.mount("#app"); //vm代表的就是Vue应⽤的根组件

在⽹⻚的 comsole 中可以通过

vm.$data.message = "bye";

来更改 Vue 组件中 data 的数值。

⼆、理解 Vue 的⽣命周期函数

Vue ⽣命周期函数: 在 ‘某⼀时刻’ 会 ‘⾃动执⾏’ 的函数

重要的四类、⼋个⽣命周期函数:

  1. Vue 实例创建函数

    beforeCreate(): 在创建 Vue 实例之前会⾃动执⾏的函数

    created(): 在 Vue 实例⽣成之后会⾃动执⾏的函数

  2. ⻚⾯渲染函数

    beforeMount(): 在组件内容被渲染到⻚⾯之前⽴即⾃动执⾏的函数

    mounted(): 在组件内容被渲染到⻚⾯之后⾃定执⾏的函数

  3. 数据更新函数

    beforeUpdate(): 当 data 中的数据发⽣变化时,会⾃动执⾏的函数

    updated(): 当 data 中的数据发⽣变化,⻚⾯重新渲染后,会⾃动执⾏的函数

  4. Vue 实例销毁函数

    beforeUnmount(): 当 Vue 应⽤失效时/销毁时,⾃动执⾏的函数

    unmounted(): 当 Vue 应⽤销毁时,且 DOM 完全销毁之后,⾃动执⾏的函数

<!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>Vue中⽣命周期函数</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      // ⽣命周期函数:在某⼀时刻⾃动执⾏的函数
      const app = Vue.createApp({
        data() {
          return {
            message: "hello world",
          };
        },
        //在 Vue 实例⽣成之前会⾃动执⾏的函数
        beforeCreate() {
          console.log("beforeCreate", this.message);
        },
        //在 Vue 实例⽣成之后会⾃动执⾏的函数
        created() {
          console.log(
            "created",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        //在组件内容被渲染到⻚⾯之前⾃动执⾏的函数
        beforeMount() {
          console.log(
            "beforeMount",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        //在组件内容被渲染到⻚⾯之后⾃动执⾏的函数
        mounted() {
          console.log(
            "mounted",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        // 当 data 中的数据发⽣变化时⾃动执⾏的函数 (可以在控制台 vm.$data.message = 'aaa')
        beforeUpdate() {
          console.log(
            "beforeUpdate",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        // 当 data中的数据发⽣变化,同时⻚⾯完成更新后,会⾃动执⾏的函数
        updated() {
          console.log(
            "updated",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        // 当 Vue 应⽤失效时⾃动执⾏的函数 (可以通过在控制台执⾏ app.unmount()模拟该操作)
        beforeUnmount() {
          console.log(
            "beforeUnmount",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        //当 Vue 应⽤失效且 DOM 完全销毁之后,⾃动执⾏的函数
        unmounted() {
          console.log(
            "unmounted",
            document.getElementById("root").innerHTML,
            this.message
          );
        },
        template: `<h2>{{message}}</h2>`,
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

三、⻚⾯插值操作

1. 插值表达式 Mustache

插值表达式 {{ }} 的使⽤,是将模型数据插⼊到⻚⾯当中。 插值表达式为什么叫 Mustache (英⽂:⼋字须)呢?

看看 {{内容}} 的两个⼤括号像不像⼋字胡⼦呢。

示例代码

<!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>Vue插值表达式</title>
  </head>
  <body>
    <div id="app">
      <p>{{firstName}} {{lastName}} (⽤插值直接显示变量)</p>
      <p>{{firstName.length}} (使⽤.访问变量的属性)</p>
      <p>{{firstName + '-----' + lastName}} (字符串的拼接)</p>
      <p>{{count * 2}} (简单的算术运算)</p>
      <p>{{firstName === 'Stephen'? '真棒':'还好'}} (三⽬运算)</p>
      <h2>
        {{lastName.split('rr').reverse().join(',')}}(使⽤Javascript函数)
      </h2>
      <p>{{customMethod(lastName)}} (调⽤⾃定义函数)</p>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            firstName: "Stephen",
            lastName: "Curry",
            count: 10,
          };
        },
        methods: {
          customMethod(str) {
            return str.split("").reverse().join(",");
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

运⾏效果

由上⾯的例⼦可以看出:

  • 插值表达式⽀持与其他的⽂字联合使⽤。
  • 也⽀持三⽬运算和算术运算。
  • 还可以使⽤ javascript 函数和⾃定义函数。
  • lastName.split(‘rr’).reverse().join(‘,’) 的作⽤是将 lastName 字符串 ‘Curry’ ⽤ ‘rr’ 分割为数组 [‘Cu’, ‘y’] , 然后数组倒序,并⽤逗号为分隔符号合并 ( join ) 字符串数组。
  • Vue 对象中的 methods 代码段是专⻔⽤于定义⾃定义函数的,我们⾃定义了函数 customMethod, 并在插值表达式中使⽤了它。

2. v-html 与 v-pre 指令的使⽤

1) v-html 指令

假如我们从服务器请求回来的是⼀个 HTML 的代码⽚段

  • 如果我们想将 html 原样输出,就是⽤{{ }}就可以了。 * 如果我们希望浏览器解析 html 后展示,那就要使⽤到 v-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>v-html指令</title>
  </head>
  <body>
    <div id="app">
      <ul>
        <!-- 错误的做法 -->
        <li>{{age}}</li>
        <li>{{link}}</li>
        <!-- 正确的做法 -->
        <li v-html="age"></li>
        <li v-html="link"></li>
      </ul>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            age: "<strong>13</strong>",
            link: '<a href="https://www.baidu.com">百度⼀下</a>',
          };
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

运⾏效果

2) v-pre 指令 如果我们想把下⾯的这段⽂字原样输出,怎么办?

Vue真有趣,特别是{{Mustache}}插值表达式

注意⽂本⾥⾯有⼀个{{Mustache}} ,Vue 会去找 Mustache 变量,找不到会报错。

即使我们定义了变量,也不满⾜我们的需求。

我们需要将 Mustache 原样输出,⽽不是交给浏览器做变量插值操作,这就需要⽤到 v-pre 指令。

代码示例:

<div id="app">
  <h2 v-pre>Vue真有趣,特别是{{Mustache}}插值表达式</h2>
</div>

运⾏效果:

3. v-text 与 v-cloak 的使⽤

1)v-text 指令

我们⽤前⾯ Vue3 的快速起步练习,先来看⼀下 Mustache 的⼀个⼩ Bug 。

浏览器由于⽹速的问题,可能会在渲染 Mustache 数据的时候发⽣延迟,导致⼀瞬间会先显示 {{message}},⽽不是 Hello Vue3。

我们可以使⽤ Chrome 浏览器来模拟这个闪屏的问题:F12->NetWork->Slow 3G (慢速 3G ⽹络)。

可以使⽤ v-text 指令来解决闪屏的问题

<!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>v-text指令</title>
  </head>
  <body>
    <div id="app">
      <!-- 使⽤v-text解决闪屏现象 -->
      <h2 v-text="message"></h2>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "hello Vue",
          };
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

运⾏效果:

  • 注意<h2 v-text="message"></h2>这⾥,我们使⽤ v-text 代替了{{message}},从⽽解决了闪屏的问题。

  • 但是要注意 v-text 并不支持这种写法 <h2 v-text="你好,message"></h2>,这样写 Vue 会将你好,message 看作插值去 data 里面找数据属性定义,而我们只定义了 message。

    所以,再到一定程度上 v-text 失去了 {{ }} 使用语法的灵活性。 * 其他的使用方法 v-text 和 {{ }} 是基本一致的。

2)v-cloak 指令

如果我们既想使用 <h2>你好,{{message}}</h2> 这种定义方式的灵活性,又想解决闪屏的问题,该怎么做呢?

可以使用 v-cloak 指令来解决

<!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>v-cloak指令</title>
    <style>
      /* v-cloak指令的样式:在DOM节点渲染完成之前不显示 */
      [v-cloak] {
        display: none;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h2 v-cloak>你好,{{message}}</h2>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Vue3",
          };
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>
  • 使⽤ v-cloak 指令并为该指令设置 display :none 的样式,⼆者结合使⽤表示在 h2 的 DOM 节点渲染完 成之前不显示你好,{{message}} ,渲染完成之后显示 你好,Vue3。
  • 注意:样式的定义要放在 head 标签⾥⾯,否则因为浏览器渲染顺序的差异,有可能不会⽣效。
  • 注意:cloak 不是 clock ,cloak 英⽂是⽃篷、披⻛的意思。这⽐较形象,我先⽤⽃篷把⾃⼰盖起来, 等我化好妆了再出来⻅⼈。

四、⽤户操作事件监听

1. v-on 事件监听指令的基本⽤法

我们在开发过程中经常需要监听⽤户的输⼊,⽐如:⽤户的点击事件、拖拽事件、键盘事件等等。

这就需要⽤到 v-on 指令。

我们通过⼀个简单的计数器的例⼦,来学习 v-on 指令的使⽤。

<!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>计数器</title>
    <style>
      [v-cloak] {
        display: none;
      }
      button {
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h2 v-cloak>counter:{{counter}}</h2>
      <button @click="counter++">+</button>
      <button @click="counter--">-</button>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            counter: 0,
          };
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>
  • 定义数据 counter,⽤于表示计数器数字,初始值设置为 0
  • v-on:click 表示当发⽣点击事件的时候,触发等号⾥⾯的表达式或者函数
  • 表达式 counter++ 和 counter– 分别实现计数器数值的加 1 和减 1 操作
  • 语法糖:我们可以将 v-on:click 简写为 @click
  • 点击加号数值加 1
  • 点击减号数值减 1

表达式只适⽤于简单的数据操作场景。如果操作⽐较复杂,我们要使⽤函数的⽅式实现。

<!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>计数器</title>
    <style>
      [v-cloak] {
        display: none;
      }
      button {
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h2 v-cloak>counter:{{counter}}</h2>
      <button @click="incr()">+</button>
      <button @click="desc()">-</button>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            counter: 0,
          };
        },
        methods: {
          incr() {
            this.counter++;
          },
          desc() {
            this.counter--;
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

运⾏效果同前

附录:js 常⽤可监听事件列表

属性 事件何时触发
abort 图像的加载被中断。
blur 元素失去焦点。
onchange 域的内容被改变。
click 当⽤户点击某个对象时调⽤的事件句柄。
dblclick 当⽤户双击某个对象时调⽤的事件句柄。
error 在加载⽂档或图像时发⽣错误。
focus 元素获得焦点。
keydown 某个键盘按键被按下。
keypress 某个键盘按键被按下并松开。
keyup 某个键盘按键被松开。
load ⼀张⻚⾯或⼀幅图像完成加载。
mousedown ⿏标按钮被按下。
mousemove ⿏标被移动。
mouseout ⿏标从某元素移开。
mouseover ⿏标移到某元素之上。
mouseup ⿏标按键被松开。
reset 重置按钮被点击。
resize 窗⼝或框架被重新调整⼤⼩。
select ⽂本被选中。
submit 确认按钮被点击。
unload ⽤户退出⻚⾯。

2. v-on 事件监听⽅法传参

我们通过点击事件监听,实现了计数器的加⼀和减⼀的操作。

如果我们想更灵活⼀点,实现加 n 和减 n 的操作,我们就需要给⾃定义的函数传参数了。

代码示例:

<!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>传参计数器</title>
    <style>
      [v-cloak] {
        display: none;
      }
      button {
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h2 v-cloak>counter:{{counter}}</h2>
      <button @click="incr(step)">+2</button>
      <button @click="desc(step)">-2</button>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            counter: 0,
            step: 2,
          };
        },
        methods: {
          incr(n) {
            this.counter += n;
          },
          desc(n) {
            this.counter -= n;
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>
  • 我们定义了步⻓变量 step,默认值为 2,作为参数传递给 incr 和 decr ⽅法。
  • incr 和 decr ⽅法接受参数,并分别做加 n 和 减 n 的操作。
  • 如果我们想动态地实现加 n,减 n,就设置 app.step = n 就可以了。

运⾏效果

  • 每点击⼀次加 2 按钮,counter 加 2;每点击⼀次减 2 按钮,counter 减 2

Vue 会默认给我们给我们⼀个参数 event ,这个参数的使⽤⽅法如下:

<button v-on:click="decr(step,$event)">-</button>

将 event 参数放在参数列表的的最后位置。注意:函数没有⾃定义参数也可以接收 event 参数。

desc(n, event) {
  this.counter = this.counter - n
  console.log(event)
}

我们将 event 参数打印出来,结果如下:

  • PointerEvent 的类型为“ mouse ”,表示⼀个⿏标产⽣的事件
  • 下图中可以看出,我们通过事件可以获取,事件产⽣的屏幕坐标、是否冒泡、事件类型 click 等信息

3. v-on 事件监听修饰符

在学习事件监听修饰符之前,我们有必要来复习⼀些基础知识。

1)什么是事件冒泡与事件捕获?

事件冒泡和事件捕获是 Dom 事件传播的两种模式,默认是冒泡模式。

  • 事件冒泡:事件从事件⽬标( target )开始,往上冒泡直到⻚⾯的最上⼀级标签。对于上⾯的例⼦,当 我们点击 div#child 的时候,⽅法 childMethod 和 parentMethod 将先后被调⽤。
  • 事件捕获:事件捕获模式与冒泡模式正好相反,事件从⽗元素向⼦元素传播。对于上⾯的例⼦,当 我们点击 div#parent 的时候,⽅法 parentMethod 和 childMethod 将先后被调⽤。

2)什么是 html 标签的默认⾏为?

  • ⽐如:标签<a>的默认⾏为是实现跳转
  • ⽐如:<input type="submit">默认⾏为是提交表单

3)事件监听的修饰符

.stop 修饰符
<!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>事件冒泡stop修饰符</title>
    <style>
      #parent {
        width: 200px;
        height: 200px;
        background-color: rgb(74, 138, 197);
      }
      #child {
        width: 100px;
        height: 100px;
        line-height: 100px;
        background-color: rgb(212, 219, 115);
        margin-left: 50px;
        margin-top: 25px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div id="parent" @click="parentMethod">
        ⽗元素
        <div id="child" @click.stop="childMethod">⼦元素</div>
      </div>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {};
        },
        methods: {
          parentMethod() {
            alert("⽗元素");
          },
          childMethod() {
            alert("⼦元素");
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

子元素加上 stop 修饰符号之后,点击⼦元素 div ,只有 childMethod ⽅法被触发,parentMethod ⽅法不会被触发。

.self 修饰符
<!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>事件冒泡self修饰符</title>
    <style>
      #parent {
        width: 200px;
        height: 200px;
        background-color: rgb(74, 138, 197);
      }
      #child {
        width: 100px;
        height: 100px;
        line-height: 100px;
        background-color: rgb(212, 219, 115);
        margin-left: 50px;
        margin-top: 25px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div id="parent" @click.self="parentMethod">
        ⽗元素
        <div id="child" @click="childMethod">⼦元素</div>
      </div>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {};
        },
        methods: {
          parentMethod() {
            alert("⽗元素");
          },
          childMethod() {
            alert("⼦元素");
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

⽗元素加上 self 修饰符之后,点击⼦元素 div,只有 childMethod ⽅法被触发,parentMethod ⽅法不会被触发。

运⾏效果同前。

.prevent 修饰符
<!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>阻⽌默认事件.prevent修饰符</title>
  </head>
  <body>
    <div id="app">
      <!-- ⽤.prevent修饰符阻⽌默认事件 -->
      <a @click.prevent="doThis" href="#">点击</a>
      <form action="/login" @submit.prevent="doThis" method="get">
        <input type="submit" value="提交" />
      </form>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {};
        },
        methods: {
          doThis() {
            alert(" ⽤.prevent修饰符阻⽌默认事件");
          },
        },
      });
      const vm = app.mount("#app");
    </script>
  </body>
</html>

加上 prevent 修饰符号之后,不会有 a 标签的默认跳转⾏为,也没有表单的提交⾏为,会调⽤ doThis() ⽅法。

注意:

修饰符号可以串联使⽤,.stop.prevent 表示先阻⽌冒泡⾏为,后阻⽌ a 标签的默认跳转⾏为。

4)事件监听修饰符总结

  • stop 修饰符,可以阻⽌事件向上级标签的冒泡⾏为。
  • self 修饰符,表示被该修饰符修饰的⽗元素不接收⼦元素的事件冒泡⾏为。
  • prevent 修饰符,可以阻⽌⼀些 html 标签的默认⾏为,⽐如 a 标签。
  • enter 修饰符(按键监听修饰符的⼀种),可以监听回⻋按键的操作。
  • once 修饰符,表示事件只可以被触发监听⼀次,以后再操作则⽆效。
  • capture 修饰符,表示开启事件传播的捕获模式,事件由⽗元素向⼦元素传播,较少⽤到。

5)按键监听修饰符

Vue 给我们定义好了⼀些常⽤的按键监听修饰符,如下:

  • .enter 监听回⻋键
  • .tab 监听 Tab 键
  • .delete (监听“删除”和“退格”键)
  • .esc 监听 ESC 键
  • .space 监听空格键
  • .up 监听”上”键
  • .down 监听”下”键
  • .left 监听”左”键
  • .right 监听”右”键

如果觉得上⾯的键盘监听修饰符不够⽤,还可以⾃定义,⽐如定义监听 F1 按键。

// 可以使⽤ `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112;

F1 按键的键盘码是 112。


文章作者: Syhan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Syhan !
评论
  目录