6.2前端笔记

【概括】:

Vue入门:Vue.js两大前端框架之一,准确的来说不能叫做框架,应该叫做渐进式框架,是后来Vue生态逐渐壮大,产生了例如Vue-router等的资源,Vue生态才逐渐变成的框架

Vue基础:

Vue指令:V-on @click 绑定时间,Vue对象是MVVM中的VM,绑定数据不需要操作DOM,V-bind:动态的绑定一个或多个 attribute,也可以是组件的 prop。

v-model(双向,v-bind是单向)

在表单输入元素或组件上创建双向绑定。

  • 期望的绑定值类型:根据表单输入元素或组件输出的值而变化

Vue的声明周期:beforeCreate,Created,Destory等,生命周期钩子 = 生命周期函数 = 生命周期事件

Vue自定义组件,建议一开始就使用驼峰命名法,

v-for中key的使用注意事项

Vue的组件化,组合复用,创建命名建议一开始就使用驼峰命名法

注意 :在 Vue 2.2.0+ 版本里,当在组件中使用 v-for 时,key 属性是必须要加上的。

这样做是因为:每次 for 循环的时候,通过指定 key 来标示当前循环这一项的唯一身份

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 "就地复用 " 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序 , 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

key的类型只能是:string/number,而且要通过 v-bind 来指定。

v-if:设置元素的显示和隐藏(添加/删除DOM元素)

作用:根据表达式的值的真假条件,来决定是否渲染元素,如果为false则不渲染(达到隐藏元素的目的),如果为true则渲染。

在切换时,元素和它的数据绑定会被销毁并重建。

举例如下:(点击按钮时,切换和隐藏盒子)

v-show:设置元素的显示和隐藏(在元素上添加/移除style="display:none"属性)

作用 :根据表达式的真假条件,来切换元素的 display 属性。如果为false,则在元素上添加 display:none属性;否则移除display:none属性。

举例如下:(点击按钮时,切换和隐藏盒子)

我们直接把上一段代码中的v-if改成v-show就可以了:

v-if和v-show的区别

v-ifv-show都能够实现对一个元素的隐藏和显示操作。

区别:

  • v-if:每次都会重新添加/删除DOM元素

  • v-show:每次不会重新进行DOM的添加/删除操作,只是在这个元素上添加/移除style="display:none"属性,表示节点的显示和隐藏。

优缺点:

  • v-if:有较高的切换性能消耗。这个很好理解,毕竟每次都要进行dom的添加/删除操作。

  • v-show:有较高的初始渲染消耗 。也就是说,即使一开始v-show="false",该节点也会被创建,只是隐藏起来了。而v-if="false"的节点,根本就不会被创建。

总结

  • 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show

  • 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if

v-on的按键修饰符

Vue 内置的按键修饰符

通俗一点讲,指的是:监听键盘输入的事件。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。如下:

Vue内置的按键修饰符:

复制代码
    .enter
    .tab
    .delete (捕获 “删除” 和 “退格” 键)
    .esc
    .space
    .up
    .down
    .left
    .right
    1.0.8+版本:支持单字母的按键别名。

比如说,keyup指的是:键盘(任何键位)抬起时的监听事件。.enter指的是:按enter键的按键修饰符。我们把这两个结合起来看看。

@keyup.enter举例:按enter键后的监听事件

@keyup.enter="addData"表示:按住enter键后,执行addData()方法。全称v-on:key.enter="addData"

我们还是拿01-04这篇文章中的列表功能来举例。之前是点击"添加"按钮后,列表中会添加一个item。现在要求:在输入框中按enter键后,也能添加一个item。

核心代码如下:

复制代码
    <input type="text" v-model="formData.name" @keyup.enter="addData">

自定义全局按键修饰符

复制代码
    //自定义全局按键修饰符
    Vue.config.keyCodes.f2 = 113;

(1)使用Vue.directive()自定义全局指令:

复制代码
<input type="text" id="search" v-model="name" v-focus>
复制代码
    //自定义全局指令 v-focus:让文本框自动获取焦点
    //参数1:指令的名称。注意,在定义的时候,指令的名称前面,不需要加 v- 前缀;但是:在`调用`的时候,必须在指令名称前 加上 v- 前缀
    //参数2:是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
    Vue.directive('focus', {
        //在每个函数中,第一个参数,永远是 el ,表示 被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象(DOM对象)
        bind: function (el) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,【只执行一次】
            // 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
            //  因为,一个元素,只有插入DOM之后,才能获取焦点
            // el.focus()
        },
        inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
            el.focus()
            // 和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效
        },
        updated: function (el) {  // 当VNode更新的时候,会执行 updated, 【可能会触发多次】
​
        }
    })

v-bind:指令绑定到元素的时候会调用函数(只有一次)

自定义指令不需要加v-,但是在html标签里的指令必须加上v- + "自定义指令名称"

由此可以看看出:bindinsertedupdated这三个钩子函数的执行时机不同,且执行的次数有区别。

复制代码
//自定义全局指令 v-color:设置DOM元素的color属性
Vue.directive('color', {
    // 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
    // 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
    // 意思是说,我们可以把样式的代码写到bind中去(即使这个时候,dom元素还没有被创建)
    bind: function (el, binding) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,【只执行一次】
​
        console.log(binding.name); //打印结果:color
        console.log(binding.value); //打印结果:green
        console.log(binding.expression);  //'green'
​
        el.style.color = binding.value// 通过bining拿到v-color中传递过来的值
​
    },
    inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
        // 和JS行为有关的操作,最好在 inserted 中去执行,防止 JS行为不生效
        //el.focus()
    },
    updated: function (el) {  // 当VNode更新的时候,会执行 updated, 【可能会触发多次】
    }
})
​
new Vue({
    el: '#app',
    data: {
        name: 'smyhvae'
    }
})
复制代码
<div id="app">
        搜索框1:
        <input type="text" id="search" v-model="name" v-color="'green'">
    </div>
       
//自定义全局指令 v-color:设置DOM元素的color属性
        Vue.directive('color', {
            // 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
            // 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
            // 意思是说,我们可以把样式的代码写到bind中去(即使这个时候,dom元素还没有被创建)
            bind: function (el, binding) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,【只执行一次】
​
                console.log(binding.name); //打印结果:color
                console.log(binding.value); //打印结果:green
                console.log(binding.expression);  //'green'
​
                el.style.color = binding.value// 通过bining拿到v-color中传递过来的值
​
            },
            inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
                // 和JS行为有关的操作,最好在 inserted 中去执行,防止 JS行为不生效
                //el.focus()
            },
            updated: function (el) {  // 当VNode更新的时候,会执行 updated, 【可能会触发多次】
            }
        })
​
        new Vue({
            el: '#app',
            data: {
                name: 'smyhvae'
            }
        })
    </script>
</body>
​
</html>

上方代码中,bind方法里传递的第二个参数binding,可以拿到DOM元素中v-color里填的值。注意,v-color="'green'",这里面写的是字符串常量;如果去掉单引号,就成了变量,不是我们想要的。

自定义私有指令

自定义私有指令 :在某一个 vue 对象内部自定义的指令称之为私有指令。这种指令只有在当前vue对象的el指定的监管区域有用。

代码举例:(设置文字的font-weight属性)

复制代码
<!DOCTYPE html>
<html lang="en">
​
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>
​
<body>
​
    <div id="app">
        <span v-fontweight="600">生命壹号</span>
    </div>
    <script>
​
        new Vue({
            el: '#app',
            data: {
                name: 'smyhvae'
            },
            //自定义私有指令
            directives: {
                'fontweight': {
                    bind: function (el, binding) {
                        el.style.fontWeight = binding.value;
                    }
                }
            }
        })
    </script>
  • vue实例的生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期。

  • 生命周期钩子:就是生命周期事件的别名而已。

生命周期钩子 = 生命周期函数 = 生命周期事件。

1、创建期间的生命周期函数

  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性

  • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板。我们可以在这里进行Ajax请求。

  • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中

  • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示。(mounted之后,表示真实DOM渲染完了,可以操作DOM了

运行期间的生命周期函数

  • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点

  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了。

PS:数据发生变化时,会触发这两个方法。不过,我们一般用watch来做。

3、销毁期间的生命周期函数

  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。

  • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

PS:可以在beforeDestroy里清除定时器、或

清除事件绑定

vue-resource的介绍

vue-resource是Vue高度集成的第三方包。

官网链接:

vue-resource 依赖于 Vue。所以,我们要按照先后顺序,导入vue.js和vue-resource.js文件。

解释

vue.js文件向Windows对象暴露了Vue这个关键词;vue-resource.js向Vue身上挂载了this.$http这个属性。于是,我们可以直接写this.$http.get或者this.$http.post或者this.$http.jsonp来调用。

vue-resource 发送Ajax请求

常见的数据请求类型包括:get、post、jsonp。下面我们分别讲一讲。

get 请求

格式举例

复制代码
this.$http.get(url)
    .then(function (result) { // 当发起get请求之后,通过 .then 来设置成功的回调函数
        console.log(result.body); // response.body就是服务器返回的成功的数据
        var result = result.body;
    },
        function (err) {
            //err是异常数据
        });
复制代码
//ajax请求:添加数据
adddata: function () {
    // 1、获取用户填写的文本框的值只需要通过this.pname即可
    // 2、调用ajax的post方法将数据上传到服务器
    var url = 'http://vueapi.ittun.com/api/addproduct';
    var postData = { name: this.pname };  //【重要】键`name`是json中约定好的字段。我们把这个字段传给服务器
    var options = { emulateJSON: true };
    this.$http.post(url, postData, options).then(function (response) {
        if (response.body.status != 0) {
            alert(response.body.message);
            return;
        }

        this.pname = '';

        // 3、添加完成后,只需要手动再调用一次getlist(将列表数据重新加载一次),即可刷新页面上的数据
        this.getlist();

    });
},

axios

除了 vue-resource 之外,还可以使用 axios 的第三方包实现实现数据的请求。

通过Vue全局配置api接口的url地址

api接口的url地址包括:绝对路径+相对路径。

我们在做Ajax请求的时候,所填写的url建议填相对路径 ,然后把绝对路径放在全局的位置。

Vue就提供了这个功能。举例如下:

如上方代码所示,第一步是在全局的位置写绝对路径

复制代码
    Vue.http.options.root = 'http://smyhvae/';

第二步是在Ajax请求的url中写相对路径 :(注意,前面不要带/

复制代码
this.$http.get('api/getprodlist')

动画进入:

  • v-enter:动画进入之前的初始状态

  • v-enter-to:动画进入之后的结束状态

  • v-enter-active:动画进入的时间段

PS:第一、第二个是时间点;第三个是时间段。

动画离开:

  • v-leave:动画离开之前的初始状态

  • v-leave-to:动画离开之后的结束状态

  • v-leave-active:动画离开的时间段

  • v-enter:动画进入之前的初始状态

  • v-enter-to:动画进入之后的结束状态

  • v-enter-active:动画进入的时间段

PS:第一、第二个是时间点;第三个是时间段。

动画离开:

  • v-leave:动画离开之前的初始状态

  • v-leave-to:动画离开之后的结束状态

  • v-leave-active:动画离开的时间段

PS:第一、第二个是时间点;第三个是时间段。

什么是组件

组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。

模块化和组件化的区别

  • 模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一

  • 组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用

全局组件的定义和注册

组件Component是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。

全局组件的定义和注册有三种方式,我们接下来讲一讲。

复制代码
 //第一步:使用 Vue.extend 定义组件
var myAccount = Vue.extend({
    template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>' // 通过 template 属性,指定了组件要展示的HTML结构。template 是 Vue 中的关键字,不能改。
});
//第二步:使用 Vue.component 注册组件
// Vue.component('组件的名称', 创建出来的组件模板对象)
Vue.component('account', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象

new Vue({
    el: '#app'
});

注意1 、红框部分,要保证二者的名字是一致的。如果在注册时,组件的名称是驼峰命名,比如:

复制代码
Vue.component('myComponent', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象

那么,在标签中使用组件时,需要把大写的驼峰改为小写的字母,同时两个单词之间使用-进行连接:

复制代码
<my-component> </my-component>

谁用标签的时候需要把自己定义的模版对象从驼峰写法改为全部小写并使用"-"进行连接

复制代码
//定义、注册组件:第一个参数是组件的名称(标签名),第二个参数是组件的定义
        Vue.component('account', {
            template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>'   // template 是 Vue 中的关键字,不能改。
        });

定义+注册一步到位

写法三:将组件内容定义到template标签中去。

代码如下:

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <!-- 定义模板 -->
    <template id="myAccount">
        <div>
            <h2>登录页面</h2>
            <h3>注册页面</h3>
        </div>
    </template>

    <div id="app">
        <!-- 使用组件 -->
        <account> </account>
    </div>

    <script>

        //定义、注册组件
        Vue.component('account', {
            template: '#myAccount'    // template 是 Vue 中的关键字,不能改。
        });

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>
复制代码
new Vue({
    el: '#app',
    data: {},
    components: { // 定义、注册Vue实例内部的私有组件
        myLogin: {
            template: '<h3>这是私有的login组件</h3>'
        }
    }


});

在Vue内部定义的是私有组件,只有当前的区域才能使用

上方代码中,如果在注册私有组件时,组件的名称是驼峰命名,比如:

复制代码
            components: { // 定义、注册Vue实例内部的私有组件
                myLogin: {
                    template: '#loginTmp'
                }
            }

那么,在标签中使用组件时,需要把大写的驼峰改为小写的字母,同时两个单词之间使用-进行连接:

复制代码
        <my-login></my-login>

所以,为了避免名字不一致的问题,我们注册组件时,组件的名称可以直接写成my-login。比如:(避免驼峰不一致的建议写法)

复制代码
components: { // 定义、注册Vue实例内部的私有组件
    `my-login`: {
        template: '#loginTmp'
    }
}

在进行组件注册的时候建议直接使用斜杠的方式注册组件名,这样在使用的时候就可以方便的直接直接使用-组件名而不用考虑驼峰转-的写法

复制代码
<div>
            <!-- 在组件的模板中,调用本组件中的data -->
            {{myData}}
            <a href="#" v-on:click="login">登录1</a>
            <h2>登录页面</h2>
            <h3>注册页面</h3>

        </div>
    </template>

    <div id="app">
        <!-- 第一次调用组件 -->
        <account> </account>
        <!-- 第二次调用组件 -->
        <account> </account>
    </div>

    <script>

        //定义、注册组件
        Vue.component('account', {
            template: '#myAccount',
            //组件中的 data
            //【注意】组件中的data,不再是对象,而是一个方法(否则报错);而且这个方法内部,还必须返回一个对象才行
            // 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
            data: function () {
                return {
                    myData: 'smyhvae'
                }
            },
            //组件中的 method
            methods: {
                login: function () {
                    alert('login操作');
                }
            }
        });

注意,在为组件添加数据时,data不再是对象了,而是function,而且要通过 return的形式进行返回;否则,页面上是无法看到效果的。通过 function返回对象的形式来定义data,作用是:

  • 上方代码中,组件<account>被调用了两次(不像根组件那样只能调用一次),但是每个组件里的数据 myData是各自独立的,不产生冲突。

  • 换而言之,通过函数返回对象的目的,是为了让每个组件都有自己独立的数据存储,而不应该共享一套数据。

组件定义时,如果要添加数据,data就换成function了,

每当我们创建一个新的组件实例时,就会调用data函数,data函数里会return一个新开辟 的对象数据。这样做,就可以保证每个组件实例有独立的数据存储

复制代码
 // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
        Vue.component('counter', {
            template: '#tmpl',
            data: function () {
                // return dataObj //当我们return全局的dataObj的时候,这个dataObj是共享的
                return { count: 0 } // 【重要】return一个**新开辟**的对象数据
            },
            methods: {
                increment() {
                    this.count++
                }
            }
        })

父组件向子组件传值

我们可以这样理解:Vue实例就是一个父组件 ,而我们自定义的组件(包括全局组件、私有组件)就是子组件

【重点】需要注意的是,子组件不能直接使用父组件中的数据。父组件可以通过props属性向子组件传值

复制代码
 <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '父组件中的数据123'
            },
            methods: {},
            components: {
                // 子组件默认无法访问到 父组件中的 data 中的数据 和 methods 中的方法
                component1: { //将子组件的名称定义为 component1
                    template: '#myTemplate',
                    data() { // 注意: 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上;
                        // data 上的数据,都是可读可写的
                        return {
                            title: '子组件私有的数据 title',
                            content: '子组件私有的数据 content'
                        }
                    },
                    // 注意: 组件中的 所有 props 中的数据,都是通过 父组件 传递给子组件的
                    // props 中的数据,都是只读的,无法重新赋值
                    props: ['parentMsg'], // 第一步:把父组件传递过来的 parentMsg 属性,先在 props 数组中,定义一下,这样,才能使用这个数据
                    directives: {},
                    filters: {},
                    components: {},
                    methods: {
                        change() {
                            // 下面这行会报错,因为子组件不要直接修改父组件中的data数据
                            // this.parentMsg = '被修改了'
                        }
                    }
                }
            }
        });
    </script>

父组件给子组件传值的步骤

根据上方截图,我们可以总结出父组件给子组件传值的步骤如下。

(1)在子组件的props属性中声明父亲传递过来的数据

(2)定义子组件的模板时,使用props中的属性

(3)父组件在引用子组件时,进行属性绑定。

子组件中,data中的数据和props中的数据的区别

  • 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上。props 中的数据,都是通过 父组件 传递给子组件的。

  • data中的数据是可读可写的;props中的属性只是可读的,无法重新赋值,重新赋值会报错(也就是说,子组件不要直接去修改父组件中的数据)。

父组件将方法传递给子组件

父组件通过事件绑定机制,将父组件的方法传递给子组件

后端路由

对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源。

当前端输入url请求资源时,服务器会监听到是什么url地址,那后端会返回什么样的资源呢?后端这个处理的过程就是通过路由分发的。

总结 :后端路由,就是把所有url地址都对应到服务器的资源,这个对应关系就是路由。

前端路由

对于单页面应用程序来说,主要通过URL中的hash(url地址中的#号)来实现不同页面之间的切换。

同时,hash有一个特点:HTTP请求中不会包含hash相关的内容。所以,单页面程序中的页面跳转主要用hash实现。

总结 :在单页应用 程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由)。

相关推荐
数智工坊1 小时前
周志华《Machine Learning》学习笔记--第十章--降维与度量学习
笔记·学习·机器学习
鹏大师运维1 小时前
统信UOS安装Subtitle Edit并使用Edge-TTS生成AI语音教程
linux·前端·人工智能·edge·麒麟·统信uos·ai语音
程序员小羊!1 小时前
02CSS预备知识
前端·css3
用户059540174461 小时前
用LangChain+Chroma实现RAG多轮对话记忆与自动化测试,把bug发现时间从2小时压缩到5分钟
前端·css
2401_868534781 小时前
常见的 vue面试题目
前端·javascript·vue.js
星栈1 小时前
Makepad UI 代码怎么读:别被语法吓住
前端·rust
胡萝卜术1 小时前
从零搭建 NLP Demo:用 ES6 模块化 + DeepSeek API 构建你的第一个 AI 应用
javascript·面试
前端市界1 小时前
实用指南:如何本地化部署 Sentry (Self-Hosted) 完整教程
前端
颂love2 小时前
TypeScript速学
前端·javascript·typescript