超详细的Vue新手向教程

一,前言

本篇文章的正文部分为渐近式介绍Vue基础中的OptionAPI和相关指令,在两大内容之外,本文结尾处会附上vue的特性。    ps:本文总字数过22000,足够详细,尽量新手向的同时也包含一些原理性知识,部分内容结合文档。

二,正文

基本流程

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{msg}}</h2>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 接下来,我们将将上述过程分开来解释

Step One. Vue应用的创建

<script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

 首先,我们通过Vue.createApp()方法构建Vue的应用对象,它需要接收一个选项对象作为参数,并且该选项对象包含了OptionAPI(data,methods,computed....) 完整见下图

但在本文中,我们只探讨一些基本的OptionAPI:

  • template
  • data
  • methods
  • computed
  • watch

Step Two. 应用实例的挂载

Vue作为国内广泛使用的渐进式框架,可以很好地与原生及其其他框架共同开发,而应用实例的挂在很好的体现了这一点,app.mount()方法可以将Vue应用在选定的DOM对象上,赋予DOM对象可以使用Vue的属性而不会影响到该DOM对象以外的内容,这样其他部分就可以使用原生JS开发而不会产生耦合。该例子中我们将应用实例挂载在id为“app”上的div元素上。

<script>
    const app = Vue.createApp(...)
    app.mount("#app")
</script>

Step Three.  template介绍

<body>
  <div id="app">

  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: `<h2>{{msg}}</h2>`,
        data() {
          return {
            msg: "Hello Vue"
          }
        }
        
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 如图,template接收DOM对象,这样Vue才能使用这些DOM对象渲染内容,为了更简便地开发,我们可以不在template中写任何内容,直接在挂载元素中写入是等价的。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{msg}}</h2>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

上述代码与实例代码是等价的。,一般都是直接在挂载元素中开发。

Step Four.  data介绍


<body>
  <div id="app">
    <h2>{{msg}}</h2>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

如图,data属性需要传入一个函数,图中的写法为语法糖,是常规写法的简便写法。在vue3中必须传入函数。data中返回的对象会被 vue响应式系统劫持,你可以认为data返回的对象中所有内容被时刻监听着,只要发生改变,这种变化也会同步到虚拟DOM上而对渲染结果产生影响。而在挂载元素中,形如{{ }}的写法被称为mustache写法,在{{}}中我们可以填入有返回值的内容,比如三元表达式,函数,变量。不支持赋值语句这样的无返回值内容,也不支持if-else语句等。这些内容后续会详细解释。在该例子中,{{ msg }}中msg显然为变量,我们可以改变data中的msg来动态改变h2中的内容。这个过程类似JS中修改innerText属性,但mustache能力更强。

 

 Step Five. methods介绍

在介绍methods前,我们先看以下案例:


<body>
  <div id="app">
    <h2>{{msg}}</h2>
    <button @click="btnClick">按钮</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            btnClick: function () {
              console.log("clicked");
            }
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

先不用管"@click"语句,它就是一个绑定事件的指令,我们观察data中,我们新增了一个对象方法,而这个方法绑定在了按钮上,我们进入网页:

 

 

结果说明这样写其实是没什么问题的,但是为了数据与方法分离,同时为了更简便地写方法,我们引入了methods这个选项式API。

使用methods后,我们可以观察变化,这一切都是等价的:


<body>
  <div id="app">
    <h2>{{msg}}</h2>
    <button @click="btnClick">按钮</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",


          }
        },
        methods: {
          btnClick() {
            console.log("clicked");
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 我们可以看到写在methods中后,这就实现了数据与方法分离的效果,减少了耦合性。这样以后修改更加简便,并且还可以使用新写法,形式上更有C的风格。在methods中的方法,我们可以通过this关键词来访问data中的数据:



<body>
  <div id="app">
    <h2>{{msg}}</h2>
    <button @click="btnClick">按钮</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",


          }
        },
        methods: {
          btnClick() {
            console.log(this.msg);
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

Notes:

在methods中不允许使用箭头函数,使用箭头函数指向的对象为window,而在window中我们不可以获取到data中的内容,那么,this到底指向什么呢?

methods 对象内的函数中的 this 关键字通常指向当前 Vue 实例。这意味着你可以通过 this 访问 Vue 实例的所有数据和属性,包括 datacomputedprops 等。

当你在 methods 中定义一个函数并调用它时,this 关键字将自动绑定到 Vue 实例上。这样你就可以在方法内部访问和修改数据属性。

Step Six. computed介绍

我们为什么需要计算属性呢?在介绍computed属性前,可以先看Mustache语法部分,再看下面的例子:

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{ msg }}</h2>
    <p>{{ getFullName() }}</p>
    <p>{{ reverseGreeting() }}</p>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            firstName: 'John',
            lastName: 'Doe',
            greeting: 'Hello Vue!'
          }
        },
        methods: {
          getFullName() {
            return this.firstName + ' ' + this.lastName
          },
          reverseGreeting() {
            return this.greeting.split('').reverse().join('');
          }
        }

      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

在上面这个例子中,我们使用methods中的方法计算了复杂的data,接下来我们使用computed属性来替代methods方法。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{ msg }}</h2>
    <p>{{ getFullName() }}</p>
    <p>{{ reverseGreeting() }}</p>
    <p>{{ fullName }}</p>
    <p>{{ reverse }}</p>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            firstName: 'John',
            lastName: 'Doe',
            greeting: 'Hello Vue!'
          }
        },
        methods: {
          getFullName() {
            return this.firstName + ' ' + this.lastName
          },
          reverseGreeting() {
            return this.greeting.split('').reverse().join('');
          }
        },
        computed: {
          fullName() {
            return this.firstName + ' ' + this.lastName
          },
          reverse() {
            return this.greeting.split('').reverse().join('');
          }
        }

      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

从形式上看,computed属性也就少个()而已,但区别还是很大的:computed中的内容存在缓存中。当firstName和lastName不发生变化时,调用fullName时就不会再计算一遍,而是直接读取。但methods中的方法不同,调用一次就计算一次。所以使用computed属性可以提升优化。

computed: {
          fullName() {
            return this.firstName + ' ' + this.lastName
          },
          reverse() {
            return this.greeting.split('').reverse().join('');
          }
        }

 

Step Seven.  watch介绍

以下的写法为app.vue中的写法,其实本质上都差不多。

说到watch,其实就是为某个变量添加一个监听器,当这个变量发生变化时就调用一个方法,监听分为浅度侦听和深度侦听。如下图,我们为msg变量设定了一个侦听器,当按下按钮,msg内容改变,侦听器启动,执行console代码。

对于watch中的监听函数,他们的名字不能随意取,必须和监听的变量名一致。

同时,监听函数触发时会返回修改前的值和修改后的值,我们可以接收这两个值。如图的newvalue和oldvalue。

<template>
  <h3>监听器</h3>
  <p>{{ msg }}</p>
  <button @click="updateHandler">更新数据</button>
</template>

<script>
export default{
  data(){
    return{
     msg:"hello",
    }
  },

  methods:{
    updateHandler(){
      this.msg = "world"
    }
  },
  watch:{
    msg(newvalue,oldvalue){
      console.log(oldvalue,newvalue);
    }
  }
}
</script>

<style>
</style>

Mustache语法

在 Vue.js 中,Mustache 语法(也称为插值语法)是一种简单的文本替换机制,用于在模板中展示数据。这种语法使用一对花括号 {{ }} 包裹表达式,表达式的结果将在渲染时插入到 HTML 中相应的位置。 

除了用作变量的显示,mustache语法也支持一些较为复杂的使用:

(1)动态属性

以下用字符串拼接为例

<div id="app">
  {{ firstName + ' ' + lastName }}
</div>
<script>
const app = Vue.createApp({
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    };
  }
});

app.mount('#app');
</script>

(2)条件语句

mustache语法只支持三元来做判断,不能使用if-else。

<div id="app">
  {{ isShow ? 'Visible' : 'Hidden' }}
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      isShow:true
    };
  }
});

app.mount('#app');
</script>

(3)方法调用

以一个反转单词的方法为例,插值语法是支持调用函数的。

<div id="app">
  {{ reverseGreeting() }}
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      greeting: 'Hello Vue!'
    };
  },
   methods:{
        reverseGreeting() {
      return this.greeting.split('').reverse().join('');
    }}

});

app.mount('#app');
</script>

 

 指令内容

这就是最新版本的所有指令了,其中,v-show,v-if,v-else,v-else-if组成了条件渲染部分,v-for大多用在迭代服务器传来的数据中,它可以依次渲染元素。v-bind用来绑定动态属性,v-on用来绑定事件,v-model用作表单处理。以上提及指令为最常用的指令,其他的指令大多是用来优化的,前期不太常用,但也会提及一部分。

(1)v-once

仅渲染元素和组件一次,并跳过之后的更新。在随后的重新渲染,元素/组件及其所有子项将被当作静态内容并跳过渲染。这可以用来优化更新时的性能。

 



<body>
  <div id="app">
    <h2 v-once>{{msg}}</h2>
    <!-- v-once只会渲染一次,后续改变不会影响这个元素了。 -->
    
    <button @click="changeInfo">改变信息</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
          }
        },
        methods: {
          changeInfo() {
            this.msg = "Hello World"
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

进入网页后,多次点击按钮文本没发生改变,但是data中的值会发生改变,v-once只是作用在渲染上,而不是限制值的修改。 

(2)v-text


<body>
  <div id="app">
    <h2 v-text="msg"></h2>
    <!-- 区别在于mustache语法更加灵活,v-text用的较少 -->
    


    <button @click="changeInfo">改变信息</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
           
          }
        },
        methods: {
          changeInfo() {
            this.msg = "Hello World"
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

mustache语法可以完全替代这个指令,了解即可,没啥用。 

(3)v-html



<body>
  <div id="app">
    <h2>{{ web }}</h2>
    <h2 v-html="web">{{ web }}</h2>

    <button @click="changeInfo">改变信息</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            web: "<a href='www.baidu.com'>百度</a>"
          }
        },
        methods: {
          changeInfo() {
            this.msg = "Hello World"
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

v-html 的内容直接作为普通 HTML 插入—— Vue 模板语法是不会被解析的。如果你发现自己正打算用 v-html 来编写模板,不如重新想想怎么使用组件来代替。 

 

 以上为vue.js文档内容,就作用上讲,v-html就是解析字符串中的内容,相当于innerHTML。但是在开发中用得不是很多,了解即可。

(4)v-pre

跳过该元素及其所有子元素的编译。

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

(5)v-cloak

在介绍v-cloak前,设想以下场景:当网站等待服务器发送数据时或者正在传输大量数据时,这会造成一定的延时,但是对于template模板却可以很快渲染完成,这时就出现骨架渲染完成但是数据却没有接收完成的现象,这是插值语法就无法渲染,这就会出现{{ msg }}这种按照原样渲染的模样,这对于用户而言是不友好的。所以我们采用v-cloak来控制这种未来得及链接数据的元素。


<style>
  [v-cloak] {
    display: none;
  }
</style>

<body>
  <div id="app">
    <h2 v-cloak>{{msg}}</h2>
    <!-- 等待渲染完成后再显示,完成前使用style属性遮掩 -->
  </div>
  <script src="../static/vue.js"></script>
  <script>
    setTimeout(() => {
      const app = Vue.createApp(
        {
          template: ``,
          data() {
            return {
              msg: "Hello Vue"
            }
          },
          methods: {

          }
        }
      )
      app.mount("#app")
    }, 3000);//延时3s
  </script>

</body>

</html>

在上述代码中,我们为应用实例化延时3s来模拟接受数据的延时情况,添加v-cloak,当未接收到msg数据时,v-cloak会启用[v-cloak]{display:none},隐藏该元素,直到msg得到数据后才会取消掉该属性。 

(6)v-bind

关于v-bind的语法糖:

<body>
  <div id="app">
    <h2>网站</h2>
    <a v-bind:href="link">百度</a>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            link: "http://www.baidu.com"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>
<body>
  <div id="app">
    <h2>网站</h2>
    <a :href="link">百度</a>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            link: "http://www.baidu.com"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

以上的两种写法完全等价,v-bind:attr="" === :attr=""。 

<1>绑定class
  • 对象语法
  • 数组语法

对象语法

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .active {
    color: red;
  }
</style>

<body>
  <div id="app">
    <!-- 最基本的绑定方法 -->
    <h2 :class="classes">Hello</h2>
    <button :class=" isActive?'active':''" @click="btnClick">我已阅读</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            classes: "a b c",
            isActive: false
          }
        },
        methods: {
          btnClick() {
            this.isActive = !this.isActive;
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

如图,观察h2的绑定class方式,classes为data中的一个变量,在calsses中,我们存有“a b c”三个类,这就是最基本的绑定类的方式,但这种绑定有个缺点:我们虽然可以通过修改classes的内容来间接的修改h2上的类,但是却不能动态的添加或者移除这个类。 

 比如我们想要实现在某种行为下附加这个类,而在其余时间不附加这个类,如果通过最基本的方式,就如button的class添加一致:通过三元运算符来判断是否启用active这个类别,这确实没问题,但是当这类动态类别数量较多时,代码可读性会很差。所以我们引入了对象语法。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .active {
    color: red;
  }
</style>

<body>
  <div id="app">
    <!-- 最基本的绑定方法 -->
    <h2 :class="classes">Hello</h2>
    <!-- 对象语法 -->
    <button :class="classes" :class="{active:isActive}" @click="btnClick">我已阅读</button>
    <!-- 静态class与动态class不会出现覆盖的问题,而是结合在一起 -->
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            classes: "a b c",
            isActive: false
          }
        },
        methods: {
          btnClick() {
            this.isActive = !this.isActive;
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

如图,对象语法很简洁,形如:

<div :class="{类别:是否启用}">

当然一个对象当然可以拥有很多元素,也就是说我们可以添加很多这样的键值对,同时控制很多对类别的启用和关闭。 这里就不演示了。

虽然说对象语法直接接收对象没问题,但是不代表对象语法只能通过对象赋值这种形式。只要返回的结果是一个可读取的对象,那这种方式就没问题,比如通过变量名引用对象,通过函数来获取对象,这都是可行的。

数组语法

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .active {
    color: red;
  }
</style>

<body>
  <div id="app">
    <button :class="classes" :class="['a','b',{'active':isActive}]" @click="btnClick">我已阅读</button>
    <!-- 静态class与动态class不会出现覆盖的问题,而是结合在一起 -->
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            classes: "a b c",
            isActive: false
          }
        },
        methods: {
          btnClick() {
            this.isActive = !this.isActive;
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

数组语法可以直接写类名(加引号),变量(不加引号),也可以写对象。数组语法用的不是很多 ,了解即可。

<2>绑定style
CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名;
  • 对象语法
  • 数组语法

对象语法

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>动态绑定style</h2>
    <p :style="{color:'red','font-size':'10px',backgroundColor:'black'}"></p>
 
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            fontColor: "red"
          }
        },
        methods: {  
    
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

如上图,对象中的键为CSS Property,它不是字符串,所以不用带引号,对于CSS property,我们有两种方式引入:如'font-size'这种中间带'-'的类型,它是作为字符串出现的,需要带引号。而'backgroundColor'这种驼峰式命名法是作为非字符串出现的,是不用带引号的,注意甄别。 

关于其他的,都和绑定class差不多,不管使用函数返回一个style对象,还是用个style的对象名来引用都是可行的。

数组语法 

<div :style="[styleObjectA, styleObjectB]"></div>

文档实例: 

<!-- 绑定 attribute -->
<img v-bind:src="imageSrc" />

<!-- 动态 attribute 名 -->
<button v-bind:[key]="value"></button>

<!-- 缩写 -->
<img :src="imageSrc" />

<!-- 缩写形式的动态 attribute 名 (3.4+),扩展为 :src="src" -->
<img :src />

<!-- 动态 attribute 名的缩写 -->
<button :[key]="value"></button>

<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName" />

<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>

<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- 绑定对象形式的 attribute -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- prop 绑定。“prop” 必须在子组件中已声明。 -->
<MyComponent :prop="someThing" />

<!-- 传递子父组件共有的 prop -->
<MyComponent v-bind="$props" />

<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>

 

<3>动态绑定属性 

形如:[attrName]="Object"

和上面的区别就是属性名变成了变量。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <p :[name]="'active'"></p>
    
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
            name: 'class',
           
          }
        },
        methods: {


        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

<4>绑定对象 

批量处理属性与对应值

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <span v-bind="infos"></span>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue",
      
            infos: {
              title: "list",
              age: 18,
              gender: "male"
            }
          }
        },
        methods: {


        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

这种情况下,v-bind:不能省略,它会接收对象将其键作为属性名,值作为属性名所对应的值,支持嵌套对象。 

(7)v-on

v-on的语法糖

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{msg}}</h2>
    <button v-on:click="btnClick"></button>
    <button @click="btnClick"></button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            msg: "Hello Vue"
          }
        },
        methods: {
          btnClick() {
            console.log("Clicked");
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

其中,

<button v-on:click="btnClick"></button>
<button @click="btnClick"></button>

完全等价。

当然,你可以选取其他触发事件条件:mousedown,mouseup等等。

<1>v-on的使用

在上文中,我们已经提及了一种事件的绑定方法,v-on同样支持多种事件的绑定。

<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

借此,我们通过v-on来构建一个计数器:

 

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{counter}}</h2>
    <button @click="btnUp">➕</button>
    <button @click="btnDown">➖</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            counter: 10
          }
        },
        methods: {
          btnUp() {
            this.counter++
          },
          btnDown() {
            this.counter--
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

<2>参数传递

当方法不需要参数时,默认将事件对象作为参数,如果方法具有参数时,使用$event来访问事件对象。

当监听原生 DOM 事件时,方法接收原生事件作为唯一参数。如果使用内联声明,声明可以访问一个特殊的 $event 变量:v-on:click="handle('ok', $event)"

<3>修饰符

以下为文档内容截取:

<!-- 停止传播 -->
<button @click.stop="doThis"></button>

<!-- 阻止默认事件 -->
<button @click.prevent="doThis"></button>

<!-- 不带表达式地阻止默认事件 -->
<form @submit.prevent></form>

<!-- 链式调用修饰符 -->
<button @click.stop.prevent="doThis"></button>

<!-- 按键用于 keyAlias 修饰符-->
<input @keyup.enter="onEnter" />

<!-- 点击事件将最多触发一次 -->
<button v-on:click.once="doThis"></button>

 

 

(8)条件指令

如图,条件渲染比较符合其他编程语言的习惯,这里就不赘述了,想要了解更多,可以看文档:

v-if文档

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h3>if测试</h3>
    <div v-if="flag">真</div>
    <div v-else>假</div>
    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else-if="type === 'C'">C</div>
    <div v-else-if="type === 'D'">D</div>
    <div v-show="type==='A'"></div>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            flag: false,
            type: "D"
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 其中,v-show的作用和v-if相似,v-show没有else的语句。

v-show与v-if的区别

当v-show条件为假时,v-show会为元素添加display:none的样式,而v-if条件为假时,元素被清除。如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;如果不会频繁的发生切换,那么使用v-if

 

(9)v-for

基于原始数据多次渲染元素或模板块。

<1>v-for的使用
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .item {
    border: 2px solid black;
    padding: 50px;
    margin-top: 2px;

  }
</style>

<body>
  <div id="app">
    <h2>电影列表</h2>
    <ul>
      <li style="list-style-type: none;" v-for="(item,index) in movies">{{ index }} {{ item }}</li>
    </ul>   
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            movies: ["速度与激情", "星际穿越", "地球脉动", "哪吒"],  
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

在python中,这种形式与enumerate()方法类似,可以同时获取到下标和对应元素。

 

<2>v-for支持类型

对于v-for而言,只要是可迭代对象,就可以作为v-for支持类型。

下面举数字,字符串和对象为例:

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .item {
    border: 2px solid black;
    padding: 50px;
    margin-top: 2px;

  }
</style>

<body>
  <div id="app">
    <h2>电影列表</h2>
    <ul>
      <li v-for="item in 10">{{ item }}</li>
      <li v-for="item in 'Hello Vue'">{{ item }}</li>
    </ul>

    

  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
           
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .item {
    border: 2px solid black;
    padding: 50px;
    margin-top: 2px;

  }
</style>

<body>
  <div id="app">
    <h2>电影列表</h2>
    

    <h2>学生列表</h2>
    <div v-for="stu in students">
      <div class="item">
        <p>ID-{{ stu.id }}</p>
        <p>Name-{{ stu.name }}</p>
        <p>Age-{{ stu.age }}</p>
        <p>Major-{{ stu.major }}</p>
      </div>
    </div>

    <div v-for="(value,key,index) in product">
      {{ index }} - {{ key }} - {{ value }}
    </div>

  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            movies: ["速度与激情", "星际穿越", "地球脉动", "哪吒"],
            //对象数组的渲染
            students: [
              { id: 1, name: "Mike", age: 18, major: "Mathmatics" },
              { id: 2, name: "Jane", age: 18, major: "Art" },
              { id: 3, name: "Rian", age: 18, major: "IT" }
            ],
            product: { id: 22, productName: "Little Prince", price: "39.8", amount: "1100" },
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

 

<3>template元素

template元素就像一个调整图层一样,它不会被渲染,它唯一的用处就是承载命令。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .item {
    border: 2px solid black;
    padding: 50px;
    margin-top: 2px;

  }
</style>

<body>
  <div id="app">
    <h2>电影列表</h2>


    <h2>学生列表</h2>
    <template v-for="stu in students">
      <div class="item">
        <p>ID-{{ stu.id }}</p>
        <p>Name-{{ stu.name }}</p>
        <p>Age-{{ stu.age }}</p>
        <p>Major-{{ stu.major }}</p>
      </div>
    </template>

    <template v-for="(value,key,index) in product">
      {{ index }} - {{ key }} - {{ value }}
    </template>

  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            movies: ["速度与激情", "星际穿越", "地球脉动", "哪吒"],
            //对象数组的渲染
            students: [
              { id: 1, name: "Mike", age: 18, major: "Mathmatics" },
              { id: 2, name: "Jane", age: 18, major: "Art" },
              { id: 3, name: "Rian", age: 18, major: "IT" }
            ],
            product: { id: 22, productName: "Little Prince", price: "39.8", amount: "1100" },
          }
        },
        methods: {

        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>
<4>数组更新检测
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。

 

以上的方法都可以刷新视图,即影响渲染结果。

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h2>{{msg}}</h2>
    <ul>
      <li v-for="item in movies">{{ item }}</li>
    </ul>

    <button @click="appendMovie">添加电影</button>
  </div>
  <script src="../static/vue.js"></script>
  <script>
    const app = Vue.createApp(
      {
        template: ``,
        data() {
          return {
            movies: ["速度与激情", "星际穿越", "地球脉动", "哪吒"]
          }
        },
        methods: {
          appendMovie() {
            this.movies.push("白蛇传");
          }
        }
      }
    )
    app.mount("#app")
  </script>

</body>

</html>

 

除了上面其中方法外,如filter(),slice(),map()这种创建新数组的方法不会被监控,即修改后必须得赋给原数组才可以引起变化。

  

<5>key

一般v-for都需要带上key作为该数据的唯一性标志,因为加上key后可以提高效率。

原理较为复杂,简单来说,就是使用了key可以使用diff算法来进行匹配key相同的VNode,而不是大量删除和修改来满足插入值的情况。

(10)v-model

v-model作为表单中最重要的指令之一,功能强大,内容比较多,这里就不赘述了,留待下篇文章讨论。这里可以提前了解一下:v-model就是可以双向绑定,当我们在input(text)中输入值时,它会实时传输给message,当我们修改message值的时候也会改变input(text)的内容,他们是互相影响的。lazy修饰词就是将实时变化改为失去焦点时变化。

<template>
  <h3>表单</h3>
  <input type="text" name="" id="" v-model="message">
  <input type="checkbox" name="" id="" v-model="check">
  <p>{{ message }}</p>
  <p>{{ check }}</p>
  <input type="text" name="" id="" v-model.lazy="message">
  <p>{{ message }}</p>
</template>

<script>
export default{
  data(){
    return{
     message:"",
     check:false
    }
  },
  watch:{
    check(newvalue,oldvalue){
      if(newvalue === true)
      {
        alert("网站协议");
      }
    
    }
  }
}
</script>

<style>
</style>

三,总结

OptionAPI(选项式API)

  • Template: 定义 Vue 实例的 HTML 模板。可以是一个字符串模板,也可以是一个外部文件的引用。
  • Data: 定义 Vue 实例的数据属性。这些属性可以在模板中使用,也可以在方法中引用。data 必须是一个函数,每次创建新实例时都会返回一个新的对象。
  • Methods:  定义可被组件内部使用的可复用函数。方法可以在模板中通过 . 符号调用,也可以通过事件监听器调用。
  • Computed: 定义依赖于其他数据属性的计算属性。计算属性会缓存结果,只有在其依赖的数据属性改变时才会重新计算。
  • Watch:  监听数据属性的变化并执行相应的回调函数。可以用于执行异步操作或开销较大的计算任务。

指令

v-once:只渲染元素和组件一次。

v-text:更新元素的 textContent

v-html:更新元素的 innerHTML

v-pre:跳过 Vue 的编译过程。

v-cloak:隐藏未编译的 Mustache 语法直到实例准备就绪。

v-bind:动态绑定属性。

v-on:绑定事件监听器。

v-for:循环渲染列表或数组。

v-model:实现表单输入控件与数据的双向绑定。

v-if....:条件渲染。

v-show:切换元素的 CSS display 属性。

四,附言

声明式与命令式

(1)声明式

定义

  • 声明式编程关注的是“做什么”,而不是“怎么做”。也就是说,你告诉计算机你想达到的目标或结果,而不是具体的步骤。
  • 声明式编程通常涉及使用高级抽象,如函数式编程、逻辑编程、数据库查询语言等。

特点

  • 更加简洁,易于理解和维护。
  • 通常更加接近人类的思考方式。
  • 可以提高代码的可读性和可维护性。
  • 适用于处理数据流和变换的场景。

示例: 在前端开发中,Vue.js 的模板系统就是一个典型的声明式编程的例子。例如,使用 v-if 指令来控制元素的显示或隐藏:

<div v-if="isVisible">Hello World</div>

这里我们声明了只有当 isVisible 为真时才显示这个元素,而不需要关心具体的实现细节。

(2)命令式

定义

  • 命令式编程关注的是“怎么做”,即明确地告诉计算机每一步应该做什么。
  • 这种编程方式更接近底层硬件的操作,通常涉及更多的控制流语句(如 for 循环、if 语句等)。

特点

  • 更加灵活,可以精确控制程序的行为。
  • 适用于需要复杂流程控制的场景。
  • 通常需要编写更多的代码来完成相同的任务。

示例: 在命令式编程中,你可能需要显式地编写循环来遍历数组并修改每个元素:

let numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
  numbers[i] *= 2;
}
  • 声明式编程:适用于构建用户界面、处理数据流、执行查询等场景。
  • 命令式编程:适用于需要精确控制流程、优化性能、处理复杂逻辑的情况。

MVVM(Model-View-ModelView)

我们可以看到ViewModel中有DOM Listeners,这个就是vue为什么能够在变量改变时快速改变渲染的原因,就和Qt中主循环效果差不多,一直循环等待修改。而Data Bindings可以参考Mustache语法,它其实就是使用Data Bindings实现的。 

 


创作不易,点个赞鼓励一下呗~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值