VUE

死了也要PY / 2023-05-12 / 原文

Vue的基本常识

Vue的使用方式

vuejs的使用官方提供了2种方式:

  1. 基于脚本导入使用,下载vue.js文件,通过script标签引入到html网页。
  2. 基于项目构建工具来进行使用,需要安装项目构建工具,自动构建成一个独立的项目。
    目前官方推荐的项目构建工具:vue-CLI,vite。

Vue调试工具Vue Devtools 谷歌浏览器插件

官网地址:https://v3.cn.vuejs.org/guide/installation.html#%E5%8F%91%E5%B8%83%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

Vue的M-V-VM思想

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,是一种代码分工思想来的。
Model 指代的就是vue对象的data选项里面的数据。这里的数据要显示到HTML页面中。
View 指代的就是vue中数据要显示的HTML页面,也称之为“视图模板” 。
ViewModel 指代的是vue.js中我们编写代码时的创建vue实例对象vm了,它是vue.js的核心,负责连接 View 和 Model,保证视图和数据的一致性,所以前面代码中,data选项里面的数据被显示中p标签中就是vm对象自动完成的。vm对象会时刻的监控View和Model的变化,并保持双方数据的一致性!!!有时候,这个特性也叫双向数据绑定
ViewModel的创建模式

<script>
        window.onload = function () {
            let vm = Vue.createApp({
                data() {
                    return {
                        test: "111"
                    }
                },
                methods() {
                },
                components: {}
            }).mount("#app1")

            console.log(vm);
            console.log(vm.num);
            console.log(vm.$data.num);
            console.log(vm.$el);  // vm对象控制的内容范围
            console.log(vm.$el.parentElement);  // vm对象本身绑定的标签元素
            console.log(vm.$refs);
            console.log(vm.$refs.p3);
            vm.$refs.p3.style["background-color"] = "red";
        }
    </script>

Vue的常用指令

指令 (Directives) 是带有“v-”前缀的特殊属性,由vue提供的。每一个指令在vue中都有固定的作用。
在vue中提供了很多指令,常用的有:{{变量名}},v-ifv-modelv-forv-html@事件名:属性名等等。
指令会在vm对象的data选项数据发生变化时,会同时改变元素中的其控制的内容或属性。
因为vue的历史版本原因,所以有一部分指令都有两种写法:

vue1.x vue2.x以后 描述
v-html v-html 输出html内容到双标签中
v-text="普通文本" {{普通文本}} 输出纯文本内容到双标签中
v-bind:属性名 :属性名 把属性中的内容当成vue变量进行输出
v-on:事件名 @事件名 绑定事件操作

Vue属性操作

vm.$data
1. createApp中的data选项,传递到vm对象内部时,已经变成了使用Proxy对象代理的属性,可以通过`vm.$data`来查询。
vm.$el
2. vm对象在经过调用mount方法绑定HTML标签以后,这个标签代表的就是当前vm对象的可控范围,可以通过`vm.$el`属性来查询,
    通过要获取绑定vm的HTML元素,可以通过`vm.$el.parentElement`来获取。

vm.$refs  # 通过$refs来抓取
3. vm对象提供$refs可以让我们开发者直接在vm控制的视图范围,使用`ref`属性绑定任意元素,并在`vm.$refs`中获取。
    vm.$refs.p3 则表示获取视图代码中的  `ref="p3"`的标签。
    $refs只能作用一次,有多个对象只有第一个生效


--------------标签属性--------------
<标签名 :标签属性="data变量名"></标签名>
<input :type="type" :checked="checked"></input>
<p :title="str1">{{ str1 }}</p> <!-- 也可以使用v-html显示双标签的内容,{{  }} 是简写 -->
<a :href="url2">淘宝</a>
<a v-bind:href="url1">百度</a>  <!-- v-bind是vue1.x版本的写法 -->
渲染后标签数据如下🔽
<input type="checkbox">
<p title="111">111</p><!-- 也可以使用v-html显示双标签的内容,{{  }} 是简写 -->
<a href="http://www.baidu2.com">百度2</a>
<a href="http://www.baidu.com">百度</a><!-- v-bind是vue1.x版本的写法 --></div>

显示/隐藏密码练习代码示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="assets/vue.global.3.2.20.js"></script>
</head>
<body>
    <div id="app">
        密码:<input :type="input_type"><button @click="show_password">{{btn_text}}</button>
    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                input_type: "password",
                btn_text: "显示密码",
            }
          },
          methods:{
            show_password(){
                // 显示密码
                if(this.input_type === "password"){
                    this.input_type = "text";
                    this.btn_text = "隐藏密码";
                }else{
                    this.input_type = "password";
                    this.btn_text = "显示密码";
                }
            }
          }
        }).mount("#app");
    </script>
</body>
</html>

Vue显示数据

  1. 在双标签中显示纯文本数据一般通过{{ }}来完成数据显示,双花括号中还可以支持js表达式和符合js语法的代码,例如函数调用. <h1>{{message}}</h1>
  2. 如果双标签的内容要显示的数据包含html代码,则使用v-html来完成 <h1 v-html="message"></h1> 和上面纯文本不同的是,v-html是以标签形式显示
  3. 表单输入框中显示数据要使用v-model来完成数据显示
    整个HTML网页组织起来就是DOM树形结构,那么vue在视图模板的时候,采用了虚拟DOM方式来展示数据的。

Vue事件绑定

基本写法

<标签名 @click="num+=5">按钮</标签名>
<标签名 @click="方法名">按钮</标签名>
<标签名 @click="方法名(参数1,参数2,....)">按钮</标签名>
vue写法 原生javascript写法 描述
@click onclick 鼠标点击事件
@dblclick ondblclick 鼠标双击事件
@submit onsubmit 表单提交事件
@focus onfocus 获取焦点事件
@blur onblur 失去焦点事件
@change onchange 值发生改变事件
.... ... ...

事件写在Vue的methods方法

商品增加减少数量
步骤:

  1. 给vue对象添加操作数据的方法
  2. 在标签中使用指令调用操作数据的方法
<body>
    <div id="app">
        <button @click="sub">-</button>
        <input type="text" v-model.number="num" size="2" @change="check_num">
        <button @click="num++">+</button>
    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                num: 0,
            }
          },
          methods: {  #定义了sub和check_num事件
            sub(){
              if(this.num<=0){
                return false;
              }
              this.num--;
            },
            check_num(){
              if(this.num<0){
                this.num = 0;
              }
            }
          }
        }).mount("#app");
    </script>
</body>

表单的数据校验练习示例

<body>
    <div id="app">
        登录账号:<input type="text" placeholder="请输入账号!" v-model="username" @blur="check_username" @focus="clear_tips('username_tip')">
        <span class="tips" ref="username_tip"></span><br>
        登录密码:<input type="password" placeholder="请输入密码!" v-model="password" @blur="check_password" @focus="clear_tips('password_tip')">
        <span class="tips" ref="password_tip"></span><br>
        确认密码:<input type="password" placeholder="请输入确认密码!" v-model="password2" @blur="check_password2" @focus="clear_tips('password2_tip')">
        <span class="tips" ref="password2_tip"></span><br>
        <input type="submit" value="注册" @click="submit_form">
    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                username: "root",
                password: "",
                password2: "",
            }
          },
          methods: {
            check_username(){
              if(this.username.length < 4 || this.username.length > 12){
                this.$refs.username_tip.innerHTML = "请输入4-12个字符长度的登录账号!";
                return true;
              }
            },
            clear_tips(name){   # 还可以进行传参
              this.$refs[name].innerHTML = ""
            },
            check_password(){
              if(this.password.length<6 || this.password.length>16){
                this.$refs.password_tip.innerHTML = "请输入6-16个字符长度的登录密码!";
                return true;
              }
            },
            check_password2(){
              // 验证密码与确认密码是否一致
              if(this.password !== this.password2){
                this.$refs.password2_tip.innerHTML = "登录密码与确认密码必须一致!";
                return true;
              }
            },
            submit_form(){
              if (this.check_username() || this.check_password() || this.check_password2() ){
                console.log("验证失败!无法提交数据");
                return false;
              }
            }
          }
        }).mount("#app");
    </script>
</body>

Vue操作样式

  • 控制标签class类名 <h1 :class="值">元素</h1> # 值可以是变量名、对象、对象的变量名、数组、数组变量名
    一共有5种写法
data(){
            return {
                cls1: "p1",
                b1: true,
                b2: true,
                p_cls1: {p1: true,p2: false},
                cls2: {p2: true,},
                cls3: {p1: true,},
                arr: [{p1: true},{p2: true},]
            }
          },
----------------------------------
<p>用法1::class属性值是一个class类名的变量</p>
<p :class="cls1">一段文本信息</p>

<p>用法2::class属性值是一个json对象</p>
<p :class="{p1: b1, p2: b2}">一段文本信息</p>

<p>用法3::class属性值是一个对象变量名</p>
<p :class="p_cls1">一段文本信息</p>

<p>用法4::class属性值是一个数组,数组的成员是data中声明的用于控制样式的json对象</p>
<p :class="[cls2,cls3]">一段文本信息</p>
<hr>

<p>用法5: :class属性值时一个数组变量名</p>
<p :class="arr">一段文本信息</p>

注意:
:class属性在同一个标签中,只能出现一次,后面出现的:class属性会被vue忽略掉,但是:class可以和class属性组合使用,class也只能在同一个标签中出现一次

<p class="p1" :class="cls2" :class="cls3">  一段文本信息</p>  这里的cls3会被忽略掉
但是下面2种形式是可以的.
<p class="p1" :class="cls2" >
<p class="p1" :class="[cls2,cls3]" >
  • 控制style样式 (很少用,一个规范不允许,另一个就是代码不好维护。)
    代码示例如下
<div id="app">
        <p>用法1::style的值是一个json对象</p>
        <p :style="{'font-size': size, color: col1}">一段文本信息</p>
        <hr>
        <p>用法2::style的值是一个对象变量名</p>
        <p :style="sty1">一段文本信息</p>
        <hr>
        <p>用法3::style的值是一个数组,数组的成员是样式组成的对象</p>
        <p :style="[sty2, sty3]"></p>
        <p>用法4::style的值是一个数组变量名</p>
        <p :style="sty_list"></p>
</div>
------------------------------
<script>
        var vm = Vue.createApp({
          data(){
            return {
                sty1: {
                  "text-align": "center",
                  "color": "yellow",
                  "background-color": "red",
                },
                sty2: {
                  "width": '150px',
                  "height": '150px',
                },
                sty3: {
                  "background-color": "red",
                },
                sty_list: [
                  obj,
                  {
                      "width": '150px',
                      "height": '150px',
                  },
                ]
            }
          },
        }).mount("#app");
    </script>

选项卡特效示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="assets/vue.global.3.2.20.js"></script>
    <style>
    p{
        padding: 0;
        margin: 0;
    }
    .title-list span{
        display: inline-block; /* 设置元素的显示模式:行级块状元素 */
        height: 60px;
        line-height: 60px;
        width: 120px;
        background-color: #bbb;
        text-align: center;
        cursor: pointer;
    }
    .title-list .activate{
        background-color: yellow;
    }
    .content-list .content{
        background-color: yellow;
        display: none;
        width: 370px;
        height: 280px;
    }
    .content-list .current{
        display: block;
    }
    </style>
</head>
<body>
    <div id="optioncard">
        <div class="title-list">
            <span :class="{activate: index === 0}" @click="index=0">国内新闻</span>
            <span :class="{activate: index === 1}" @click="index=1">国际新闻</span>
            <span :class="{activate: index === 2}" @click="index=2">银河新闻</span>
        </div>
        <div class="content-list">
            <div class="content" :class="{current: index === 0}">
                <p>国内新闻列表</p>
                <p>国内新闻列表</p>
                <p>国内新闻列表</p>
                <p>国内新闻列表</p>
                <p>国内新闻列表</p>
            </div>
            <div class="content" :class="{current: index === 1}">
                <p>国际新闻列表</p>
                <p>国际新闻列表</p>
                <p>国际新闻列表</p>
                <p>国际新闻列表</p>
                <p>国际新闻列表</p>
            </div>
            <div class="content" :class="{current: index === 2}">
                <p>银河新闻列表</p>
                <p>银河新闻列表</p>
                <p>银河新闻列表</p>
                <p>银河新闻列表</p>
                <p>银河新闻列表</p>
            </div>
        </div>
    </div>
    <script>
    var vm = Vue.createApp({
      data(){
        return {
           index: 0,
        }
      },
      methods: {

      }
    }).mount("#optioncard")
    </script>
</body>
</html>

Vue条件渲染

  • vue中提供了两个指令可以用于判断是否要显示元素,分别是v-if和v-show。
    前者是渲染前作判断,如果不显示,则不会出现在html源码中
    后者只是用display属性
<div id="app">
      <p v-if="username">欢迎回到xx网站,尊敬的{{username}}!</p>
      <p v-else>欢迎访问xx网站,尊敬的游客!</p>
      <p v-if="level === 0" class="l0">您是vip会员!</p>
      <p v-else-if="level === 1" class="l1">您是svip会员!</p>
      <p v-else-if="level === 2" class="l2">您是mvip会员!</p>
      <p v-else-if="level === 3" class="l3">您是msvip会员!</p>
      <p v-else>您是签到会员!</p>
</div>
  • vue列表渲染指令 通过v-for指令可以将一组数据渲染到页面中,数据可以是数组或者对象
    v-for的形参
<div v-for="(item, index) in items"></div>
<div v-for="(value, key) in object"></div>
<div v-for="(value, name, index) in object"></div>

代码示例



数据是数组:        
        <ul>
            <!--book是列表的每一个元素-->
            <li v-for="book in book_list">{{book.title}}</li>
        </ul>

        <ul>
            <!--book是列表的每一个元素,index是每个元素的下标-->
            <li v-for="(book, index) in book_list">第{{ index+1}}本图书:{{book.title}}</li>
        </ul>


        <script>
            var vm1 = new Vue({
                el:"#app",
                data:{
                    book_list:[
                        {"id":1,"title":"图书名称1","price":200},
                        {"id":2,"title":"图书名称2","price":200},
                        {"id":3,"title":"图书名称3","price":200},
                        {"id":4,"title":"图书名称4","price":200},
                    ]
                }
            })
        </script>

数据是对象:
        <ul>
            <!--i是每一个value值-->
            <li v-for="value in book">{{value}}</li>
        </ul>
        <ul>
            <!--i是每一个value值,j是每一个键名-->
            <li v-for="attr, value in book">{{attr}}:{{value}}</li>
        </ul>
        <script>
            var vm1 = new Vue({
                el:"#app",
                data(){
                    return {
                        book: {
                            // "attr":"value"
                            "id":11,
                            "title":"图书名称1",
                            "price":200
                        },
                	}
                }
            })
        </script>

Vue对象以及对象的API

所谓的选项API就是在实例化vm对象时,往createApp中传递进行选项参数,例如,我们已经使用过的data或者methods就是选项api。

过滤器

Vue3.0已经被淘汰了过滤器这个选项,可以在methods里进行自定义函数实现过滤
代码示例 书本数量不能小于0

<body>
    <div id="app">
        <table class="table">
            <tr>
                <th>序号</th>
                <th>商品名</th>
                <th>价格</th>
                <th>购买数量</th>
                <th>单品统计</th>
            </tr>
            <tr v-for="(goods, key) in goods_list" :class="{bg: goods.price>100}">
                <td>{{key+1}}</td>
                <td>{{goods.name}}</td>
                <td>{{goods.price}}</td>
                <td>
                    <button @click="sub(goods)">-</button>
                    <input type="text" size="1" v-model="goods.num">
                    <button @click="goods.num+=10">+</button>
                </td>
                <td></td>
            </tr>
        </table>

    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                goods_list: [
                    {"name":"python入门","price":150, num: 0},
                    {"name":"python进阶","price":100, num: 0},
                    {"name":"python高级","price":75, num: 0},
                    {"name":"python研究","price":60, num: 0},
                    {"name":"python放弃","price":110, num: 0},
                ]
            }
          },
          methods:{
            sub(goods){
              goods.num-=10;
              if(goods.num<0){
                goods.num = 0;
              }
            }
          }
        }).mount("#app")
    </script>
</body>

计算和监听属性

  • 计算属性,
    是vue提供给我们开发者用于编写代码时保存计算出新的数据结果的变量。主要通过computed选项进行声明的。
<body>
    <div id="app">
        <input type="text" size="1" v-model.number="num1">+
        <input type="text" size="1" v-model.number="num2">={{result}}
    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                num1: 10,
                num2: 10,
            }
          },
          computed: {  // 计算属性选项API,里面的成员就是一个属性方法,用于保存在vm中其他变量的计算结果
            result(){
                return this.num1+ this.num2
            }
          }
        }).mount("#app")
    </script>
</body>
  • 侦听属性
    侦听属性,可以帮助我们侦听data某个数据的变化,从而做相应的自定义操作。
    侦听属性是一个对象,它的键是要监听的对象或者变量,值一般是函数,当侦听的data数据发生变化时,会自定执行的对应函数,这个函数在被调用时,vue会传入两个形参,第一个是变化前的数据值,第二个是变化后的数据值。
    主要通过watch选项进行声明的。
div id="app1">
    <label for="user">输入账号</label>
    <input type="text" id="user" ref="username" v-model="username">
</div>
<script>

            let vm = Vue.createApp({
                data() {
                    return {
                        username:""
                    }
                },
                watch:{
                    // 侦听data中的username
                    username(new_data, old_data){
                        console.log(new_data,new_data.length)
                        if (new_data.length<6){this.$refs.username.style.border="1px solid red"}
                        else{this.$refs.username.style.border="1px solid black"}
                    }
                }
            }).mount("#app1")
        
    </script>

当然用事件绑定实现这个功能 为了效果明显css设置一下,不要外边框颜色input{outline: None;}

<div id="app1">
    <label for="user">输入账号</label>
    <input type="text" id="user" ref="username" v-model="username" @keypress="user_listen(username)">
</div>
<script>

    let vm = Vue.createApp({
        data() {
            return {
                username: ""
            }
        },
        methods:{
            user_listen(username){
                if (username.length < 6) {
                    console.log(username)
                    this.$refs.username.style.border = "1px solid red"
                } else {
                    console.log(">6")
                    this.$refs.username.style.border = "1px solid black"
                }
            }
        },
        // watch: {
        //     // 侦听data中的username
        //     username(new_data, old_data) {
        //         console.log(new_data, new_data.length)
        //         if (new_data.length < 6) {
        //             this.$refs.username.style.border = "1px solid red"
        //         } else {
        //             this.$refs.username.style.border = "1px solid black"
        //         }
        //     }
        // }
    }).mount("#app1")

</script>

生命周期

每个vm对象在创建时都要经过一系列的初始化过程。在这个过程中Vue.js会自动运行一些叫做生命周期的的钩子函数,我们可以使用这些函数,在对象创建的不同时间阶段加上我们需要的自动执行代码,就实现特定的功能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="assets/vue.global.3.2.20.js"></script>

</head>
<body>
    <div id="app">
        <p ref="p1">{{message}}</p>
        <input type="text" v-model="message">
    </div>
    <script>
        var vm = Vue.createApp({
          data(){
            return {
                message: "hello",
            }
          },
          beforeCreate(){
            // 当前函数执行时,vm还没有初始化完成。
            console.log("beforeCreate>>>", this.$data);
            console.log("beforeCreate>>>", this.$el);
            console.log("beforeCreate>>>", this.$refs);
          },
          created(){
            // 当前函数执行时,vm对象已经初始化完成
            console.log("created>>> $data=", this.$data);  // 此时data选项中的数据已经被注入到vm对象中
            console.log("created>>> $el=", this.$el);
            console.log("created>>> $refs=", this.$refs);
            // 在开发中,我们可以在这个函数中进行初始化数据相关的操作,例如:使用ajax从服务器中读取数据,并赋值给data
          },
          beforeMount(){
            // 已经把对应的vue语法的变量替换成了html内容了,但是并没有挂载到el标签的内容中
            console.log("beforeMount>>> $el=", this.$el);
            console.log("beforeMount>>> template=", this.$options.template);
            console.log("beforeMount>>> $refs=", this.$refs);
          },
          mounted(){
            // vue生成的HTML内容已经挂载到了$el属性中
            console.log("mounted>>>", this.$el);
            console.log("mounted>>>", this.$refs);
          },
          beforeUpdate(){
            // 变量更新前,data选项中的数据发生了改变,但是没有重新生成虚拟DOM,所以HTML中的变量值没有被同步
            console.log("beforeUpdate>>>", this.$data);
            console.log("beforeUpdate>>>", this.$el.parentElement.innerHTML);
            // 修改数据前,判断本次修改是否合法?发送ajax,
          },
          updated(){
            // 变量更新后,html内容已经与data选项中的数据同步了,因为重新生成了虚拟DOM
            console.log("updated>>>", this.$el.parentElement.innerHTML);
            // 修改数据后,发送ajax,同步数据库
          }
        }).mount("#app")
    </script>
</body>
</html>

在vue使用的过程中,如果要初始化操作,把初始化操作的代码放在 mounted 中执行。
mounted阶段就是在vm对象已经把data数据实现到页面以后。一般页面初始化使用。例如,用户访问页面加载成功以后,就要执行的ajax请求。
另一个就是created,这个阶段就是在 vue对象创建以后,把ajax请求后端数据的代码放进 created

指令修饰符

指令修饰符,用于编写在vue执行之后的补充符号,作用是增强当前指令或给当前指令进行功能的调整的。
v-model的指令修饰符。
v-model.trim 用于去除字符串两边的空白字符,常用于密码
v-model.lazy 用于减少触发watch侦听选项的频率,从原来的input输入事件的侦听切换成了change值改变事件的监听
v-model.number 表示把变量作为数值来进行转换提取,能转的都会转换
常用的修饰符
.stop - 调用 event.stopPropagation(),禁止事件冒泡。
.prevent - 调用 event.preventDefault(),阻止事件默认行为。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器