Vue2学习知识点统计

容器与vue实例的关系

点击查看代码
 <h3>Vue与容器是一对一绑定关系,即使有多个容器,Vue也只能处理一个,后续容器将不再处理</h3>
    <!-- 准备容器 -->
    <div class='anbin'>
        {{age}}
    </div>
    <div class='anbin'>
        {{age}}
    </div>


    <!-- Vue程序 -->
    <script>
        /* new Vue({
            el: '.anbin',
            data: {
                age: 50
            },
        }) */

        let option = {
            el: '.anbin',
            data: {
                age: 'hello'
            }
        }

        new Vue(option)

    </script>
  1. new Vue得到的是vue的实例对象,vue文档中把这个实例命名为vm,所以一般说vm就是值vue的实例
  2. 容器就是要被渲染的HTML元素,例如上述的<div class="anbin"></div>,就是一个容器
  3. 容器与vue实例的关系是一 一对应的,可以理解为现代法律规则的一夫一妻制,不允许出现多个容器对应一个vm,也不允许出现多个vm对应一个容器,当容器/vm重复渲染时,vue只会编译渲染一个,后续的将不再编译。
  4. js中声明的变量,无法被vue识别使用

插值语法

点击查看代码
<!-- 容器 -->
    <div id="anbin">
        <div>
            <p>渲染变量字符串:{{msg}}</p>
            <p>
                渲染变量函数: {{sayHello()}}
            </p>
            <p>
                渲染变量常量: {{one}}
            </p>
        </div>

        <br>

        <div>
            <code>表达式:能返回结果值的js代码</code>
            <p>
                渲染常量表达式 : {{1+10}}
            </p>
            <p>
                渲染常量字符串拼接表达式 : {{'my ' + 'name ' + 'is ' + 'anbin'}}
            </p>
            <p>
                渲染字符串和常量拼接表达式: {{'msg' + 1}}
            </p>
            <p>
                渲染三元运算表达式:{{one ? '真' : '假'}}
            </p>
            <p>
                渲染变量常量数值和常量数值计算表达式:{{one + 1}}
            </p>
            <p>
                渲染方法表达式:{{msg.split('').reverse().join('')}}
            </p>
        </div>

        <br>
        <div>
            <code>vue内置了一些全局变量的白名单,在白名单中的全局变量,可以配合其方法,用来当作表达式</code>
            <br>
            <p>
                全局变量有这些:
                <code>
                    Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,require
                </code>
            </p>
            <p>调用某个全局变量Date的now方法值为:{{Date.now()}}</p>
        </div>

        <h3>
            <code>使用let、var、const等js变量:不可以被vue识别渲染,控制台会报错:{{age}}---{{name}}--{{hobby}}</code>
        </h3>
    </div>
    <!-- vue实例 -->
    <script>
        // 自定义一些全局变量,给上面测试使用
        var age = 18;
        let name = 'anbin';
        const hobby = 'coding';

        new Vue({
            el: '#anbin',
            data: {
                msg: 'helloVue',  //字符串
                one: 1,  //常量 
                sayHello: function say() {  //函数
                    console.log('say sayHello Success!')
                }
            }
        })
    </script>

插值语法就是HTML中被花括号包裹的变量值
插值语法用于向页面插入数据,以供被页面正常渲染
一般来说数据来源由data提供,但跳过data直接在页面中使用常量也是可以的,例如上述的{{1+10}}将输出11
所以插值语法准确来说:是将任意的值插入到HTML页面中,同时支持任何表达式;为什么说支持表达式?因为表达式必须返回一个结果值,所有不能返回结果值的js代码都不被插值语法认可
插值语法支持多种变量类型的表达式,例如上述的变量+常量变量+变量三元运算变量使用方法等等...
参考文档:插值

指令

点击查看代码
<div id="anbin">
        <div>
            <p>{{msg}}</p>
        </div>

        <div>
            <p>
                <code>v-once:让值只编译一次,后续当值发生变化时不重新编译,从而提升页面性能</code>
            </p>
            <p>
                <code>v-if:if条件判断</code>
                <code v-if=" ten>nine ? true : false ">{{res}}</code>
            </p>
            <p>
                <code>v-bind:绑定动态属性,用于动态操作属性的改变</code>
                <br>
                <!-- v-bind绑定的src属性,改变image_path变量的值,动态更换图片路径,以实现页面图片的动态切换-->
                <img v-bind:src="image_path" width="150">
            </p>
			 <p>
            v-model指令: <input type="text" v-model:value="nameTwo">
            </p>
        </div>

    </div>
    <script>
        new Vue({
            el: '#anbin',
            data: {
                msg: 'hello vue',
                nine: 9,
                ten: 10,
                res: '你看到我了',
                image_path: '/favicon.ico',
				nameTwo: '李四',
            }
        })
    </script>
  1. vue中所有指令都是以属性的方式存在
  2. v-once:用于只编译一次数据,后续更改数据将不会重新编译,即不会重新渲染这个值
  3. v-if:用于条件分支中的if判断; v-if的判断条件中要写表达式,例如 v-if="1>0"
  4. v-bind:用于动态的操作HTML元素属性的值,例如想动态的更改img标签中的src图片路径、动态更改超链接中的href网址,就可以使用到。
  5. v-model:用于表单操作,从view层响应式地更改数据到model层、有使用限制:只能用于:input、textarea、select等html元素和component组件中,其余地方使用无效;通俗易懂的来说,使用v-model必须得有一个更改数据的入口,如果没有那就不能使用。
    参考文档:指令

函数默认对象

点击查看代码
<body>

    <div id="anbin">
        <p>
            <button @click="layerOne">点我触发弹窗,不传递函数参数版本</button>
            <br>
            <code>
                当不需要向函数中传递参数时,函数可以省略小括号(),此时函数只有一个参数<br/>
                那就是event对象作为参数,注意是自动的隐示接收,直接在函数括号中声明event对象即可,参照layerOne  <br>
                但不建议这么做,会造成可读性极差后期难以维护
            </code>

        </p>
        <p>
            <button @click="layerTwo($event,'你好')">点我触发弹窗,函数需要开发者自定义传递参数版本</button>
            <br>
            <code>
                此时在函数中要获取event对象,就必须使用$event来显示声明参数,参照layerTwo
            </code>
        </p>
    </div>
    <script src="/js/vue2.js"></script>
    <script>
        new Vue({
            el: '#anbin',
            data: {

            },
            methods: {
                layerOne(event) {
                    console.log('button对应的event对象被传入了',event)
                    alert('隐示调用')
                },
                layerTwo(event, content) {
                    console.log(event)
                    alert('显示调用:' + content)
                }
            }
        })
    </script>

</body>
  1. 当模板中声明函数,不传任何参数且不写括号时,会向函数中隐示传递传递event对象参数,可以在对应的方法中接收并打印,例如此处的layerOne
  2. 不建议在模板中声明函数,使用这种不传递任何参数且省略括号的行为,这会造成可读性极差难以维护的情况
  3. 当模板中使用了括号传递参数时,要获取event对象,则需要在括号内使用$event来显示接收,且参数位置需一一对应,例如此处的layerTwo

this指向与箭头函数

点击查看代码
<body>
    <div id="anbin">
        <h4>关于事件回调函数中的this指向问题</h4>
        <p>
            <button @click="addNumber">点我使用<code style="color: green;">普通函数</code>实现第一个计数器,<code
                    style="color: green;">正常运行</code></button>
            <code>现在number的值是:{{number}}</code>
        </p>
        <p>
            <button @click="addInt">点我使用<code style="color: red;">箭头函数</code>实现第二个计数器,发现<code
                    style="color: red;">无法成功</code></button>
            <code>现在int的值是:{{int}}</code>
        </p>
    </div>
    <script src="/js/vue2.js"></script>
    <script>
        // 此处vm是此处Vue实例对象
        const vm = new Vue({
            el: "#anbin",
            data: {
                number: 1,
                int: 100
            },
            methods: {
                // 普通函数
                addNumber() {
                    alert('去查看控制台,观察信息')
                    console.log('this是vm吗:', this === vm);
                    console.log('既然this是vm,那他们取number值是一样的吗:', vm.number === this.number);
                    console.log('此处this对象是:', this)
                    this.number++;
                },
                // 箭头函数
                addInt: () => {
                    alert('去查看控制台,观察信息')
                    console.log('this是vm吗:', this === vm);
                    console.log('既然this是vm,那他们取int值是一样的吗:', vm.int === this.int);
                    /* 
                        此处无法成功
                        是因为vue中正常情况下,this实际是Vue实例对象本身,this代表的作用域也就是Vue实例对象作用域
                        而箭头函数本身没有作用域,this的作用域只能从父级继承获得,而箭头函数的父级就是整个页面的window对象,所以这里的this实际是window而不是vue
                    */
                    console.log('此处this对象是:', this)
                    this.int++;
                },
            }
        })
    </script>
</body>
  1. 首先我们知道vm就是模板中的Vue实例对象
  2. 在普通函数中,使用的this取值,这个this其实就是vm,也就是这个Vue实例对象,所以this的作用域是这个Vue实例对象的作用域,也就可以正常的从Vue实例对象中取值了,例如此处this.number
  3. 在箭头函数中,箭头函数本身是没有this这个概念的,也就是说箭头函数本身没有作用域,
  4. 需要继承父级作用域来当做箭头函数本身的作用域,那么此时this就不会是Vue实例对象了,而是最外层最原始js的window对象,也就是说this的作用域就是window对象的作用域,那么使用this.int自然就取不到Vue实例对象中的int值了,因为二者作用域都不在一块
    参考文档:

computed计算属性(完整写法)

点击查看代码
<div id="app">
        <h3>{{msg}}</h3>
        <p>
            <b>需求:在input框中输入字符串,通过处理后在页面上渲染 字符串被反转后的 结果。</b>
        </p>

        <div>
            输入的信息
            <input type="text" v-model="content">
        </div>
        <br><br><br>


        <div>
            <b>第1种方式:methods实现(这里故意调用多次methods,查看console是否执行了多次运算)</b>
            <div>反转后的信息
                {{splitReverseStr()}}
            </div>
            {{splitReverseStr()}}
            {{splitReverseStr()}}
        </div>
        <br><br><br>

        <div>
            <b>第2种方式:computed实现</b>
            <div>反转后的信息
                {{cReverseStr}}
            </div>
        </div>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '计算属性----反转字符串',
                content: ''
            },
            methods: {
                // 反转字符串
                splitReverseStr() {
                    console.log('执行methods中的字符串运算')
                    return this.content.split('').reverse().join('')
                }
            },
            computed: {
                // 定义一个计算属性:cReverseStr
                cReverseStr: {
                    get() {
                        console.log('触发了computed计算')
                        return this.content.split('').reverse().join('')
                    },
                    set(valuie) {
                        console.log(value)
                    }
                }
            }
        })
    </script>
  1. methods和compute都可以实现需求,但更推荐使用computed
  2. methods方式实现较为死板,因为是methods是一个函数,所以在页面上调用多少次就会执行多少次。假如返回值是一个长期不变确定的值,使用这种方式会造成效率低下原因(因为不会针对同一个值缓存,
    而是呆板的重复运算,造成资源浪费
  3. computed则很好的解决了methods的这一痛点,computed底层会自行将执行的结果值存储起来,
    当下一次调用改computed时,会优先判断本次结果值 是否与 上次产生的结果值相等
    如若相等则直接返回上一次的结果值,不进行计算处理,有效的提升了性能与节省资源

参考文档:计算属性
计算属性缓存 vs 方法

computed计算属性的简写方式

点击查看代码
<div id="app">
    <h3>{{msg}}</h3>
    <p>
        <b>
            需求:在input框中输入字符串,通过处理后在页面上渲染 <br>
            计算属性简写方式得到的 <br>
            反转字符串的结果
        </b>
    </p>
    <div>
        输入的信息
        <input type="text" v-model="content">
    </div>
    <br>
    <div>
        compuetd结果值:{{cReverseStr}}
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            msg: '计算属性简写形式',
            content: ''
        },
        computed: {
            // 计算属性的简写
            cReverseStr() {
                console.log('触发了computed计算')
                return this.content.split('').reverse().join('')
            }
        }
    })
</script>
  1. 通过定义cReverseStr()的方式来简写computed的写法
  2. 这里的cReverseStr()是一个计算属性,而不是函数方法,请不要误解
  3. 什么时候使用computed的简写写法?
    当只需要获取计算属性的值时(就是当get时
  4. 什么时候使用computed的完整写法? 当你不仅需要获取计算属性的值,还需要对计算属性的值进行修改时(不仅需要get,还需要set时

watch侦听属性(完整写法)

点击查看代码
    <div id="app" v-cloak>
        <h3>{{msg}}</h3>
        <div>
            <b>{{know}}</b>
            <ul>
                <li v-for="(item , key) in info">{{item}}</li>
            </ul>
        </div>
        <div>
            <p>
                数字:{{number}}
            </p>
            <button @click="add">点我让数字递增,去控制台查看变化</button>
            <br>
        </div>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                msg: '侦听属性的变化',
                know: '其余知识点',
                info: ['watch的immediate配置项', 'watch可以监听(data和computed中)任意属性'],
                number: 0,
            },
            methods: {
                add() {
                    console.log('触发methods', 'add');
                    return this.number++;
                }
            },
            computed: {
                hehe() {
                    console.log('触发computed');
                    return ' 哈哈 ' + this.number
                }
            },
            watch: {
                // 这里监听了data中的普通属性值:number
                number: {
                    immediate: true,
                    deep: true,
                    handler(newValue, oldVaule) {
                        console.log(`触发 number属性  的watch`, oldVaule, newValue);
                    }
                },
                // 这里监听了computed的计算属性值:hehe
                hehe: {
                    immediate: true,
                    deep: true,
                    handler(newValue, oldVaule) {
                        console.log('触发 hehe属性  的watch', oldVaule, newValue);
                    }
                }
            },
        })
    </script>
  1. watch侦听属性用于监听一个属性值的变化

  2. 这里使用了watch侦听属性监听了data属性中的number属性,也监听了computed的hehe属性,所以我们知道watch不仅可以监听普通data中的属性,还可以监听computed的属性,没有局限场景

  3. watch侦听某个属性,当属性值发生后,会自动向该属性的watch中传入两个参数
    第一个是发生变化后的新值,第二个是变化前的旧值,参数名可以随意定义 这里为了更好的理解,我定义了newValue表示新值,oldVue表示旧值

  4. watch的完整写法中,有2个配置项可以进行配置,这是可选的,并不是一定要写

  5. 第一个配置项:immediate
    作用:当页面初始化(一打开页面开始加载的时候)就执行watch侦听某个属性,哪个属性配置了immediate就一开始监听,没配置的则不进行监听

  6. 第二个配置项:deep
    作用:当你的data数据是一个多层级数据时,进行该配置项的配置,可以直接监听到最深层级的对象值
    需要注意的是,当对象的层级太多时,会产生监听不到旧值的情况(这与vue的浅拷贝和深拷贝相关,涉及到内存,不甚了解

  7. handler
    作用:watch侦听属性,侦听到属性发生变化后,需要做一些逻辑操作,而逻辑操作就是在这个hanlder方法中实现的
    需要注意的是:完整写法中 处理逻辑的方法名称必须是hanlder,不可以是其他

参考文档:侦听器

watch侦听属性的简写方式

点击查看代码
<div id="app">
    <h3>{{msg}}</h3>
    <div>
        <b>{{know}}</b>
        <ul>
            <li v-for="(item , key) in info">{{item}}</li>
        </ul>
    </div>
    <div>
        <p>
            数字:{{number}}
        </p>
        <button @click="add">点我让数字递增,去控制台查看变化</button>
        <br>
    </div>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: '侦听属性的变化',
            know: '其余知识点',
            info: ['watch的immediate配置项', 'watch可以监听(data和computed中)任意属性'],
            number: 0,
        },
        methods: {
            add() {
                console.log('触发methods', 'add');
                return this.number++;
            }
        },
        computed: {
            hehe() {
                console.log('触发computed');
                return ' 哈哈 ' + this.number
            }
        },
        watch: {
            number(newValue, oldVaule) {
                console.log(`触发 number属性  的watch`, oldVaule, newValue);
            },
            hehe(newValue, oldVaule) {
                console.log('触发 hehe属性  的watch', oldVaule, newValue);
            }
        },
    })
</script>
  1. 当不需要使用deep深度监听属性,也不需要使用immediate来执行页面初始化监听;同时满足这两者条件时,可以使用watch的简写写法来实现监听属性
  2. 例如这里的number和hehe,同样一个是监听data中的数据,一个是监听hehe中的数据,与完整写法一样可以实现功能,只是写法更为简便了

watch和computed选择哪个?

  1. compuetd和watch都能完成某个功能
  2. 不需要执行异步操作时:选择computed,因为computed是同步操作,不支持异步
  3. 需要执行异步/开销较大(耗时久)的操作时:选择watch
  4. 这里的异步,举个例子:3秒后执行一段逻辑/执行ajax请求
    参考文档:计算属性 vs 侦听属性

表单提交

点击查看代码
  <div id="app" v-cloak>
        <h3>{{msg}}</h3>
        <form>
            <!-- 使用trim修饰符配合v-model,将输入的值去除前后空格 -->
            <p>用户名:<input type="text" v-model.trim="user.user_name"></p>
            <p>密码:<input type="password" v-model="user.password" autocomplete="off"></p>
            <!-- 使用number修饰符配合v-model,将输入的值由字符串类型强转为number类型 -->
            <p>年龄:<input type="number" v-model.number="user.age"></p>
            <p>
                性别:
                <input type="radio" id="one" value="man" v-model="user.sex" checked>
                <label for="one">男</label>
                <input type="radio" id="two" value="woman" v-model="user.sex">
                <label for="two">女</label>
            </p>
            <p>
                爱好:
                <input type="checkbox" id="运动" value="运动" v-model="user.hobby">
                <label for="运动">运动</label>
                <input type="checkbox" id="旅游" value="旅游" v-model="user.hobby">
                <label for="旅游">旅游</label>
                <input type="checkbox" id="唱歌" value="唱歌" v-model="user.hobby">
                <label for="唱歌">唱歌</label>
                <br>
            </p>
            <p>
                <span>学历: &nbsp;</span>
                <select v-model="user.edu">
                    <option disabled value="">请选择</option>
                    <option value="zk">专科</option>
                    <option value="bk">本科</option>
                    <option value="yjs">研究生</option>
                </select>
            </p>
            <p>
                简介:
                <!-- 使用lazy修饰符配合v-model,在数据改变时进行收集,而不是每次修改都收集 -->
                <textarea name="introduction" id="" cols="50" rows="20" v-model.lazy="user.introduction"></textarea>
            </p>
            <p>
                <input type="checkbox" id="checkbox" v-model="user.checked">
                <label for="checkbox"> 阅读并接收协议</label>
            </p>

            <p>
                <!-- 使用prevent事件修饰符阻止页面刷新,嵌套使用stop修饰符阻止事件往外(上)层(html结构)继续传播 -->
                <button @click.prevent.stop="register">注册</button>
            </p>

        </form>
    </div>
    <script src="/js/vue2.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                'msg': '收集表单数据',
                // 这里把表单信息使用user对象包裹起来ed目的是为了下面methods中方便只获取user对象中的表单信息
                user: {
                    user_name: '',
                    password: '',
                    age: '',
                    sex: 'woman',  //给予sex用于渲染表单初始sex字段默认值
                    hobby: [],
                    edu: '',
                    introduction: '',
                    checked: false,
                },
            },
            methods: {
                register(event) {
                    console.log('vue中data属性的所有值', this.$data)
                    console.log('user表单信息', this.$data.user)
                    console.log('要传给后端的user表单信息', JSON.stringify(this.$data.user))
                }
            }
        })
    </script>

这里把表单信息使用user对象包裹起来的目的,是为了methods中更方便的只获取user对象中的所有表单字段信息,避免收集到其他data数据,影响业务
参考文档:表单输入绑定

filter过滤器

点击查看代码
<body>
    <div id="root" v-cloak >
        <h2>{{msg}}</h2>
        <b>假如content是后端返回的数据,要求当数据不是0.65时,页面渲染'-'字符串,否则正常显示</b>
        <ul>
            <li>第1种:通过计算属性实现</li>
            <li>第2种:通过过滤器实现</li>
        </ul>
        <p>刷新页面查看每次不同的值 </p>
        <p>
            计算属性实现: {{getRes}}
        </p>
        <p>
            过滤器实现: {{content|filterRes}}
        </p>
        <div>45245</div>
    </div>
</body>
<script src="/js/vue2.js"></script>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            msg: '过滤器',
            content: [null, 'undefined', 0.65],
            methodsContent: '',
        },
        computed: {
            getRes() {
                const index = Math.floor(Math.random() * this.content.length)
                console.log('计算属性实现', index, this.content[index])
                const res = this.content[index]
                const arr = ['', undefined, null]
                return arr.indexOf(res) >= 0 ? '-' : res;
            }
        },
        // 过滤器
        filters: {
            filterRes(value) {
                console.log('过滤器实现', value);
                const index = Math.floor(Math.random() * value.length)
                const res = value[index]
                const arr = ['', undefined, null]
                return arr.indexOf(res) >= 0 ? '-' : res;
            },

        }
    })
</script>
  1. filters过滤器类似于自定义函数,可以对data数据进行处理后再渲染到页面上
  2. 在filters中定义一个过滤器的名称,我这里起名叫filterRes
  3. filterRes()接收一个参数,那就是data值,filterRes(){}中编写过滤器要实现的逻辑,用于返回渲染在页面上的data值
  4. filters过滤器可以定义多个,并且可以一直调用
    此处对content属性使用了filterRes过滤器进行数据渲染
    其实还可以定义第二个过滤器,例如叫filterTwo
    将原有的页面渲染从{{content|filterRes}}改写为{{content|filterRes|filterTwo}}
  5. 由于filters实现逻辑和computed实现逻辑类似,所以vue3中觉得filters似乎没有存在的必要,砍掉了该功能,推荐用户在computed/methods中自行定义实现,但基于缓存机制,所以优先推崇使用computed实现
    参考文档:过滤器

生命周期

点击查看代码
<div id="root">
        <div>
            <p>计数器</p>
            <button @click="add">点我增加</button>
            <p>{{num}}</p>
            <p>
                <input type="text" v-model="num">
            </p>
        </div>
    </div>
    <script>
        new Vue({
            el: "#root",
            data: {
                num: 1
            },
            methods: {
                add() {
                    return this.num++;
                }
            },
            beforeCreate() {
                console.log('数据代理创建前')
            },
            created() {
                console.log('数据代理创建后')
            },
            beforeMount() {
                console.log('vue实例对象数据挂载前')
            },
            mounted() {
                console.log("vue实例对象数据挂载后")
            },
            beforeUpdate() {
                console.log("vue实例对象数据更新前")
            },
            updated() {
                console.log("vue实例对象数据更新后")
            },
            beforeDestroy() {
                console.log("vue实例对象被销毁前")
            },
            destroy() {
                console.log("vue实例对象被数据销毁后")
            }
        })
    </script>
  1. 参考文档:生命周期图示
  2. vue的生命周期包含4个阶段,8个钩子函数,也就是说:1个阶段对应2个钩子函数
  3. 其中每个钩子函数的作用已经在console.log()中写明
  4. 需要注意的是beforeDestroy和destroy这两个钩子函数较为特殊,因为只有当vue实例被销毁时才会触发,这种行为都是当用户关闭页面才会产生vue实例对象的销毁,所以我们一般看不到这两个钩子函数的conosle.log
  5. 可以在不同的生命周期钩子函数中,做一些不同的逻辑处理,例如异步请求,页面数据初始化自定义处理等操作过滤器
posted @ 2023-10-14 09:49  Anbin啊  阅读(36)  评论(0)    收藏  举报