Vue复习笔记

Vue复习笔记

一、脚手架创建Vue项目

1.1 首先需要node环境
  • 去node官网下载node应用,然后安装就行了,版本就选最新的,node自带npm包管理器

  • 在npm中安装淘宝依赖(cnpm)会比npm快速的安装插件

    • npm install -g cnpm --registry=https://registry.npm.taobao.org
      
1.2 使用npm全局安装脚手架
  • npm install -g @vue/cli
    
1.3 使用脚手架初始化vue项目(新版本)
  • vue create 项目名 **新版脚手架命令
    //接下来可选择vue3.x还是vue2.x
    

二、vue的基础语法

0 项目代码参考:

  1. 01vue初体验,
  2. 02插值的操作,
  3. 03动态绑定属性,
  4. 04计算属性,
  5. 05事件监听v-on,
  6. 06条件判断,
  7. 07v-for的使用,
  8. 08购物车案例,
  9. 09v-model的使用

2.1 Hello Vue


    <div id="app">
        {{message}}<br />
        {{name}}
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                message:'Hello Vue!',
                name:'spa'
            }
        });
    </script>

代码解读:当使用vue的时候,需要创建一个vue的实例,new Vue时需要传入一个对象对象中的属性有el(用来挂载管理的标签#app,它的类型可以是string也可以是HTMLElement节点),data(用来定义数据,可以在受管理的标签中直接使用这些定义好的数据,它的类型是Object或者Function),methods(定义方法,它的类型是Object,里面可以存放多种方法)

2.2 计数器案例

	<div id="app">
        <p>当前计数:{{count}}</p>
        <!-- 普通用法 -->
        <!-- <button v-on:click="count++">加1</button>
        <button v-on:click="count--">减1</button> -->
        <!-- 绑定函数 -->
        <button v-on:click="increment">加1</button>
        <button v-on:click="decrement">减1</button>
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                count:0
            },
            methods:{
                increment(){
                    console.log('我加了');
                    this.count++;
                },
                decrement(){
                    console.log('我减了');
                    this.count--;
                }
            }
        });
    </script>

代码解读:通过本案例学习到了methods属性(用来定义方法),还学习到了v-on指令的使用,v-on指令的语法糖为@符号

2.3 mvvm概念

​ view:视图,其实就是我们的DOM节点

​ model:就是我们抽离出来的数据,存放在data属性里

​ viewmodel:我们实例化出来的vue对象,它就像是一个处理器一样,连接view和model俩端

2.4 v-if和v-show

	<div id="app">
        <p v-show="isShow">是否显示</p>
        <button @click="changeH">切换</button>
    </div>
    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                isShow:true
            },
            methods: {
                changeH(){
                    this.isShow = !this.isShow;
                }
            },
        });
    </script>

​ 1. if是vue的一个内部指令,作用于HTML中,根据表达式的值的真假条件,销毁或重建元素;

​ 2. v-show根据表达式之真假值,切换元素的 display CSS 属性

2.5 v-for

	<div id="app">
        <ul>
            <li v-for="item in movies">{{item}}</li>
            <button @click="changeArr">更新</button>
        </ul>
    </div>
    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                movies:['海王','星际穿越','大话西游','肖申克的救赎']
            },
            methods:{
            	changeArr(){
                    //1.通过arr[]的方式更新数组的值,不是响应式的
                    //this.arr[0] = 'dddd'

                    //2.push,pop,sheft,unsheft,splice,reverse等方法都是响应式的

                    //Vue自己实现的set(更新的对象,更新的下标,更新的值)
                    //Vue.set(this.arr,0,'ddd')
                }
            }
        });
    </script>

代码解读:v-for指令是循环渲染一组data中的数组,需要以 item in movies形式items是源数据数组并且item是数组元素迭代的别名。通过数组的下标(arr[index])去改变数组的值时,vue不是响应式的,也就是说vue不会监听这种改变

2.6 v-once

	<div id="app">
        <p>{{message}}</p>
        <!-- 即使改变message变量的值,加了v-once指令的标签也只渲染一次,从此不再发生改变 -->
        <p v-once>{{message}}</p>
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                message:'hello world'
            }
        });
    </script>

2.7 v-text和v-html

当我们网速很慢或者javascript出错时,会显示{{xxx}};Vue提供的v-text、v-html可以解决这个问题;

<script src="/assets/js/vue.js"></script>
<div id="app">
	<p v-text="message">hello</p>
	<span v-html="msgHtml">abc </span>
</div>
<script>
      var app = new Vue({
          el:'#app',
          data:{
              message:'hello vue',
              msgHtml:'<h2>wellcome to vue world!</h2>'
          }
      })
</script>

2.8 v-pre

	<div id="app">
        <!-- 原封不动的解析,而不会触发mustache语法 -->
        <h2 v-pre>{{message}}</h2>
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                message:'{{message}}'
            }
        });
    </script>

2.9 v-on

v-on 就是监听事件,可以用v-on指令监听DOM事件来触发一些javascript代码;

还可以使用@click代替v-on

<html> <head> <title>Add</title> <script src="/assets/js/vue.js"></script> </head> <body> <div id="von"> <p>number:{{num}}</p> <button v-on:click="add">+</button> <button v-on:click="sub">-</button><br/> <button @click="add">加</button> <button @click="sub">减</button> </div> <script>
            new Vue({
                el:'#von',
                data:{
                    num:100
                },
                methods:{
                    add:function(){
                        this.num = this.num + 1;
                    },
                    sub:function(){
                        this.num --;
                    }
                }
            });
        </script> </body> </html>

2.10 v-on的修饰符

	<div id="app">
        <!-- 1.阻止事件冒泡(.stop) -->
        <div @click="clickDiv">
            aaaaassss
            <button @click.stop="btn">按钮</button>
        </div>

        <!-- 2.阻止默认事件(.prevent) -->
        <form action="baidu">
            <input type="submit" value="提交" @click.prevent="submitClick">
        </form>

        <!-- 3.监听键盘的按键(enter:回车键) -->
        <input @keyup.enter="press" type="text" />

        <!-- 4.once:只触发一次 -->
        <button @click.once="ddd">dddd</button>
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                count:0
            },
            methods: {
                clickDiv(){
                    console.log('div');
                },
                btn(){
                    console.log('btn');
                },
                submitClick(){
                    console.log('1111');
                },
                press(){
                    console.log('抬起');
                },
                ddd(){
                    console.log('once');
                }
            },
        });
    </script>

2.11 v-model

​ 绑定数据源:就是把数据绑定在特定的表单元素上,可以很容易的实现双向数据绑定;我们需要vue实例可以帮我们渲染数据并响应式的监听数据修改,同时我们还需要监听用户行为,如果用户在标签上面修改了数据我们需要获取到数据可以使用v-mode指令;

	<div id="app">
        <!-- 主要是inpute事件和v-bind的结合就能实现v-model -->
        <!-- <input type="text" :value="val" @input="changeInput"> -->
        
        <!-- 上面的简写 -->
        <input type="text" :value="val" @input="e => val = e.target.value">
        <h3>{{val}}</h3>
    </div>
    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:"#app",
            data:{
                val:''
            },
            methods: {
                changeInput(e){
                    this.val = e.target.value;
                }
            },
        });
    </script>

2.12 v-model的修饰符

	<div id="app">
        <!-- 1.修饰符:lazy -->
        <!-- lazy修饰符只有在你失去焦点或按下回车键的时候才会,把值绑定,这样可以避免频繁的触发双向绑定 -->
        <input type="text" v-model.lazy="message">
        <h2>你的值是:{{message}}</h2>

        <!-- 2.修饰符:number -->
        <!-- 控制绑定值数字输入,但是好像有bug,先输入数字可以只记录数字,先输入字符则会变成字符串(v-model会把值转换成String类型) -->
        <input type="text" v-model.number="age">
        <h2>您的数字是:{{age}}--{{typeof age}}</h2>

        <!-- 3.修饰符:trim -->
        <!-- 去除绑定值左右俩边的空格 -->
        <input type="text" v-model.trim="name">
        <h2>您的名字是:{{name}}</h2>
    </div>
    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:"#app",
            data:{
                message:'',
                age:0,
                name:''
            }
        });
    </script>

2.13 v-bind

v-bind是处理HTML中的标签属性的

在html中用v-bind:src=”imgSrc”的动态绑定了src的值,这个值是在vue构造器里的data属性中找到的;

v-bind的语法糖为:冒号(😃

 	<div id = "vbind"> 
 		<!-- v-bind图片 --> 
 		<p><img v-bind:src="imgSrc" @click="change"/></p>
 	</div> 		
 	<script>
            new Vue({
                el:'#vbind',
                data:{
                    imgSrc:'assets/img/01_af.jpg'
                },
                methods:{
                    change:function(){
                        this.imgSrc = 'assets/img/01_csd.jpg'
                    }
                }
            }) ;
     </script>

2.14 v-bind动态绑定class

	<div id="app">
        <!-- 动态绑定的方式 -->
        <!-- <h2 :class="{class名:布尔值}">class绑定</h2> -->
		
		<!-- 对象形式 -->
        <h2 :class="{active:isactive,lice:islice}">class绑定</h2>
        <button @click="changeColor">点我变色</button>
        
        <!-- 数组形式 -->
        <h2 :class="[active,lice]">class绑定</h2>
    </div>

    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                isactive:true,
                islice:true
            },
            methods: {
                changeColor(){
                    this.isactive = !this.isactive;
                }
            },
        });
    </script>

2.15 计算属性(computed)

	<div id="app">
        <h2>{{firstName+' '+lastName}}</h2>
        <h2>{{firstName}} {{lastName}}</h2>
        <!-- 使用计算属性 -->
        <h2>{{fullName}}</h2>
    </div>
    <script src="../vue/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                firstName:'spa',
                lastName:'ll'
            },
            computed:{
                fullName(){
                    return this.firstName+' '+this.lastName
                }
            }
        });
    </script>

​ 注意:我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的

三、Vue的生命周期

生命周期:某个事物从诞生到消亡的过程

3.1 生命周期图示

在这里插入图片描述

3.2 生命周期函数

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

created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板

beforeMount:此时已经完成了模板的编译,生成了虚拟节点,但是还没有挂载到页面中,此时还不可操作dom节点

mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示

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

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

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

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

四、组件化开发

0 项目代码参考:10组件化开发

4.1 创建组件

	<div id="app">
        <cpn></cpn>
    </div>

    <template id="cpn">
        <div>
            <h1>{{title}}</h1>
            <h2>haha</h2>
            <h3>xixixixixixi</h3>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        Vue.component('cpn', {
            template: '#cpn',
            data() {
                return {
                    title: 'cpn组件'
                }
            },
        })
        const app = new Vue({
            el: '#app'
        });
    </script>

​ 代码解读:通过Vue的component方法,注册组件,参数1:组件名,参数2:组件实例对象

​ 组件实例对象:

​ 1.template:定义组件的模板,可以通过template标签定义,这里传入标签的id号

​ 2.data:必须为函数,且返回一个新的实例对象

​ 3.其它参数,参考Vue实例…

4.2 组件中的data为什么是函数

	<div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

    <template id="cpn">
        <div>
            <h2>当前计数:{{count}}</h2>
            <button @click="increment">+</button>
            <button @click="decrement">-</button>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        Vue.component('cpn', {
            template: '#cpn',
            //如果不是函数,每次调用组件都不会返回新的对象,就无法使得每个组件都有自己的数据.
            //这样导致的后果是每个组件都用同一份数据,这样组件的灵活性就没了.
            data() {
                return {
                    count: 0,
                }
            },
            methods: {
                increment(){
                    this.count++;
                },
                decrement(){
                    this.count--;
                }
            },
        })
        const app = new Vue({
            el: '#app'
        });
    </script>

4.3 组件间通信

组件之间通信也叫,组件间的状态传递,它是联系组件与组件的桥梁

4.3.1 父传子
	<div id="app">
        <cpn :cmovies="movies" :cmessage="message"></cpn>
    </div>


    <template id="cpn">
        <div>
            {{cmovies}}
            <hr>
            {{cmessage}}
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            data() {
                return {
                    
                }
            },
            //1.普通传递
            //props:['cmovies'],
            //2.传递的时候进行:类型限制
            props:{
                cmovies:Array,
                cmessage:{
                    type:String, //类型为字符串
                    default:'aaaaa', //设置默认值
                    required:true //必须传入,否则报错   
                }
            }
        }
        const app = new Vue({
            el:'#app',
            data:{
                movies:['海王','看不见的客人','秘密访客'],
                message:'hello world!'
            },
            components:{
                cpn
            }
        });
    </script>

代码解读:

​ 1.通过prop传递,在子组件添加自定义属性,通过v-bind绑定此属性,然后将要传的数据作为属性的值

​ 2.子组件通过props属性接收,接收后可以作为data数据一样使用

​ 3.不要在子组件中直接修改父组件传过来的值,如要修改可以将父组件传来的值作为初始值,赋值给data,作为组件内部的数据使用

4.3.2 子传父
	<div id="app">
        <!-- 
            子传父:
                1.在子组件中通过$emit()方法定义事件,参数1:'自定义事件名',参数2:要传给父组建的参数
                2.在父组件中通过v-on指令监听自定义事件,然后在监听的回调中取得数据
         -->
        <cpn @itemclick="getChild"></cpn>
    </div>


    <template id="cpn">
        <div>
            <button v-for="item in categroies" :key="item.id" @click="getData(item)">{{item.name}}</button>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        //定义子组件
        const cpn = {
            template:'#cpn',
            data() {
                return {
                    //类别
                    categroies:[
                        {
                            id:'aaa',
                            name:'热门推荐'
                        },
                        {
                            id:'bbb',
                            name:'手机数码'
                        },
                        {
                            id:'ccc',
                            name:'电脑办公'
                        }
                    ]
                }
            },
            methods: {
                getData(item){
                    //子传父:1.通过自定义事件
                    this.$emit('itemclick',item);
                }
            },
        }
        const app = new Vue({
            el:'#app',
            data:{
                
            },
            // 注册子组件
            components:{
                cpn
            },
            methods: {
                //2.在父组件中取得数据
                getChild(item){
                    console.log(item);
                }
            },
        });
    </script>

代码解读:
1.在子组件中通过$emit()方法定义事件,参数1:‘自定义事件名’,参数2:要传给父组建的参数
2.在父组件中通过v-on指令监听自定义事件,然后在监听的回调中取得数据

4.3.3 父访问子
	<div id="app">
        <cpn ref="cpn"></cpn>
        <button @click="getChildren">按钮</button>
    </div>


    <template id="cpn">
        <div>
            <h2>我是子组件</h2>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            data() {
                return {
                    
                }
            },
            props:{
            },
            methods: {
                showMessage(){
                    console.log('message');                    
                }
            },
        }
        const app = new Vue({
            el:'#app',
            data:{
                
            },
            components:{
                cpn
            },
            methods: {
                getChildren(){
                    //通过$children获取到的是所有的子组件,它是数组
                    //this.$children[0].showMessage();
                    
                    //这种方法用的很多
                    //通过$refs:需要在子组件上加上ref属性值为子组件名字,然后通过$refs.设置的名字获取到相应的子组件
                    this.$refs.cpn.showMessage();
                }
            },
        });
    </script>

代码解读:

​ 1.通过 r e f s : 需 要 在 子 组 件 上 加 上 r e f 属 性 值 为 子 组 件 名 字 , 然 后 通 过 refs:需要在子组件上加上ref属性值为子组件名字,然后通过 refs:ref,refs.设置的名字获取到相应的子组件

4.3.4 子访问父
	<div id="app">
        <cpn ref="cpn"></cpn>
    </div>

    <template id="cpn">
        <div>
            <h2>我是子组件</h2>
            <button @click="getParent">按钮</button>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        const cpn = {
            template: '#cpn',
            data() {
                return {

                }
            },
            props: {},
            methods: {
                getParent() {
                //使用较少
                    //通过$parent访问父组件
                    console.log(this.$parent);

                    //访问根组件:通过$root
                    console.log(this.$root);
                }
            },
        }
        const app = new Vue({
            el: '#app',
            data: {

            },
            components: {
                cpn
            },
            methods: {

            },
        });
    </script>

代码解读:

​ 1.访问父组件:使用$parent

​ 2.访问根组件:使用$root

4.4 插槽(slot)

4.4.1 插槽的使用

插槽的使用:

​ 1.基本使用:

​ 2.默认值:

4.4.2 具名插槽
	<div id="app">
        <cpn>
            <button slot="left">按钮</button>
            <span slot="center">标题</span>
            <span slot="right">右边</span>
        </cpn>
    </div>

    <template id="cpn">
        <div>
            <!-- 定义具名插槽:
                1.给slot添加name属性
                2.使用的时候,传入要替换的标签,然后标签上添加slot属性它的值为name的值
            -->
            <slot name="left"></slot>
            <slot name="center"></slot>
            <slot name="right"></slot>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            data() {
                return {
                    
                }
            },
            methods:{

            }
        }
        const app = new Vue({
            el:'#app',
            data:{

            },
            methods: {
                
            },
            components:{
                cpn
            }
        });
    </script>

代码解读:

​ 1.在组件的slot标签上设置name为插槽取名字

​ 2.在使用时,通过slot属性和第一步的name值,指定要替换的插槽

4.4.3 作用域具名插槽
	<div id="app">
        <cpn>
            <div slot-scope="slot">
                <p v-for="item in slot.data">{{item}}</p>
            </div>
        </cpn>
        <cpn>
            <p slot-scope="slot">{{slot.data.join('-')}}</p>
        </cpn>
    </div>

    <template id="cpn">
        <div>
            <!-- 作用域具名插槽:
                1.给slot添加v-bind绑定的自定义属性,它的值为要传给父组件使用的变量名
                2.使用的时候,在组件的根标签上设置slot-scope属性,它的值为slot(可以自定义字符串),然后使用的时候,通过				  slot.自定义属性,取得数据
                3.总结:父组件替换插槽的标签,但内容由子组件来提供
            -->
            <slot :data="movies"></slot>
        </div>
    </template>

    <script src="../vue/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            data() {
                return {
                    movies:['海王','肖申克的救赎','霸王别姬','真三国演绎']
                }
            },
            methods:{

            }
        }
        const app = new Vue({
            el:'#app',
            data:{

            },
            methods: {
                
            },
            components:{
                cpn
            }
        });
    </script>

代码解读:

​ 作用域具名插槽:
​ 1.给slot添加v-bind绑定的自定义属性,它的值为要传给父组件使用的变量名
​ 2.使用的时候,在组件的根标签上设置slot-scope属性它的值为slot(可以自定义字符串),然后使用的时候,通过slot.自定义属性取得值
​ 3.总结:父组件替换插槽的标签,但内容由子组件来提供

五、Vue-cli

创建项目:vue create 项目名

六、Vue-router

0 项目代码参考:12vue-router

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得轻松;这里的路由并不是指我们平时所说的硬件路由器,而是SPA(单页应用)的路径管理器也就是说vue-router就是我们WebApp的链接路径管理系统

6.1 vue-route的安装

npm install vue-router

yarn add vue-router

6.2 建立router文件夹和index.js文件

//路由配置
import Vue from 'vue';
import VueRouter from 'vue-router';

/* 路由懒加载(lazy):用import的方式导入哦*/
const Home = () => import('../components/Home.vue');
const About = () => import('../components/About.vue');
const User = () => import('../components/User.vue');


/* 非懒加载方式
import Home from '../components/Home.vue';
import About from '../components/About.vue';
import User from '../components/User.vue'; */

//源码中执行install方法,我想大概是在初始化插件吧
Vue.use(VueRouter);

const routes = [
    {
        path:'/',
        redirect:'/home'
    },
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    },
    {
        path:'/user/:uname',
        component:User
    }
];

const router = new VueRouter({
    mode:'history',
    routes,
    linkActiveClass:'active'
});

export default router;

6.3 将导出的router文件挂载到Vue实例身上

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

6.4 使用

<template>
  <div id="app">
    <h1>我是App组件</h1>
    <!-- 1.声明式导航 
      <router-link>:
        to属性:对应跳转的路径
        tag属性:将<router-link>标签,渲染成指定的标签,默认渲染为<a></a>标签(已被弃用,但还没被移除)
        replace属性:相当于调用了history.replaceState({},"","url")方法,使得网页的后退失效
        router-link-active:组件唤醒时自动添加的class,这个默认class可以通过linkActiveClass属性在router里面配置
     -->
    <router-link to="/home" replace tag="button">首页</router-link>
    <router-link to="/about" replace tag="button">关于</router-link>
      
    <!-- 2.函数式导航
      通过$router对象:
        push(url)
        replace(url)
    -->
    <!-- <button @click="toHome">首页</button>
    <button @click="toAbout">关于</button> -->
      
    <!-- 
      3.动态路由:
        1.需要在路由(routes)里面的path后面,接一个  /:user
        2.跳转到定义了动态路由的组件时,需要在地址后面跟上参数,以确保路由正确匹配
        3.一般来说后面的参数需要使用v-bind绑定上去
     -->
    <router-link :to="'/user/'+uname" replace tag="button">用户</router-link>

    <!-- 
      4.关于$router和$route的区别:
        1.$router对象是vue-router在定义时new出来的全局对象,它已经挂载到了Vue实例的身上了,在任何组件中都可以访问到
        2.$route对象是当前处于活跃状态的组件的路由实例对象,它里面记载了params(动态路由传参),query(地址栏传参),命名组件(name),等参数信息
        3.这俩个对象非常重要
     -->

    <!-- 5.组件占位符 -->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      uname:'spa'
    }
  },
  methods: {
    //编程式导航的测试代码
    toHome() {
      this.$router.push("/home");
    },
    toAbout() {
      this.$router.push("/about");
    },
  },
};
</script>

<style>
/* 测试活跃状态的组件样式 */
.router-link-active {
  color: red;
}
.active {
  color: blue;
}
</style>

6.5 路由的嵌套使用

在需要嵌套的组件下面添加children属性,然后在父组件中添加标签占位

children:[
            //注意:子路由的path前面无需加 / 
            {
                path:'',
                redirect:'/home/news'
            },
            {
                path:'news',
                component:HomeNews
            },
            {
                path:'message',
                component:HomeMessage
            }
        ]

6.6 传递参数的方式

6.6.1 params类型:
  • 配置路由格式:/router/:id

  • 传递的方式:在path后面跟上对应的值

  • 传递后形成的路径:/router/123,/router/abc

  • 获取:this.$route.params取得包含所有的动态路由传来的参数

6.6.2 query类型:
  • 配置路由格式:/router,也就是普通配置
  • 传递的方式:对象中使用query的key作为传递的方式
  • 传递后形成的路径:/router?id=123,/router?id=abc
  • 获取:this.$route.query取得包含所有参数的对象

6.7 导航守卫

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象变化,或使用 beforeRouteUpdate 的组件内守卫。

7.7.1 全局守卫

前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError()

确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错

示例:

//全局前置路由守卫(其实就是一个钩子函数)
router.beforeEach(function (to,from,next) { 
    //从from到to
    //通过document.title设置网页的标题
    document.title = to.matched[0].meta.title;
    console.log(to,from);

    //执行下一步,不写的话会导致路由在此终断
    next();
});

后置守卫

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  // ...
})
7.7.2 路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

这些守卫与全局前置守卫的方法参数是一样的。

7.7.3 组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdatebeforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}
7.7.4 完整的导航解析流程
  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

6.8 keep-alive标签

6.8.1 使用场景

在搭建 vue 项目时,有某些组件没必要多次渲染,所以需要将组件在内存中进行‘持久化’,此时 便可以派上用场了。 可以使被包含的组件状态维持不变,即便是组件切换了,其内的状态依旧维持在内存之中。在下一次显示时,也不会重现渲染。

6.8.2 生命周期钩子

被包含在 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

activated
在组件被激活时调用,在组件第一次渲染时也会被调用,之后每次keep-alive激活时被调用。

deactivated
在组件被停用时调用。

注意:只有组件被 keep-alive 包裹时,这两个生命周期才会被调用,如果作为正常组件使用,是不会被调用,以及在 2.1.0 版本之后,使用 exclude 排除之后,就算被包裹在 keep-alive 中,这两个钩子依然不会被调用!另外在服务端渲染时此钩子也不会被调用的。

6.8.3 配合router-view使用

有些时候可能需要将整个路由页面一切缓存下来,也就是将 进行缓存。这种使用场景还是蛮多的

keep-alive 新加入了两个属性: include(包含的组件缓存生效) 与 exclude(排除的组件不缓存,优先级大于include)

include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。
当使用正则或者是数组时,一定要使用 v-bind !

注意:

先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。

不会在函数式组件中正常工作,因为它们没有缓存实例。
当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前vue 2.4.2 version)。比如:包含于排除同时匹配到了组件A,那组件A不会被缓存。
包含在 中,但符合 exclude ,不会调用activated 和 deactivated。

七、tabbar插件(slot)

0 项目代码参考:13vue-tabbar

本案例主要使用到vue的插槽技术,自定义了一个功能较为灵活的TabBar组件

TabBar组件可以通过传入icon和text文本来生成自己想要的tabbar,还能传入选中文字的颜色来控制tabbar的风格

组件的设计思路:

​ 1.首先把样式在一个组件里面先写好,然后再一步步抽取出来

​ 2.然后按层级抽取子组件,比如一个完整的TabBar包含TabBarItem(也就是一个选项,一个选项对应一个页面)

​ 3.一个TabBarItem里面又包含,icon和text,这样又抽出来一个子组件

​ 4.在TabBar组件中,可以使用占位,这样就能接收n个TabBarItem组件了,然后TabBarItem组件中,可以使用具名插槽(),因为TabBarItem中的icon和text是分别固定的,这时只需要在TabBarItem组件中,定义俩个插槽并分别命名

​ 5.如果要使得TabBar组件的TabBarItem,在选中的时候文本和icon高亮,就需要在TabBarItem中定义第三个插槽,用来显示选中时的TabBarItem,并且每个插槽都需要包裹一个div用来绑定v-if和click事件(slot会被传入的元素替换掉,所以无法绑定属性)

八、vuex

0 项目代码参考:14vuex

8.1 vuex的概念

vuex就是一个全局的单例模式,把需要共享的状态(数据)交给vuex管理,当vuex管理的时候,存取状态都需要按照vuex的格式来操作,这样才能保证数据的准确性

8.2 vuex数据流程图

在这里插入图片描述

数据流图解读:

​ State-----通过Render渲染到组件-----VueComponent-----组件内通过Dispatch分发异步操作-----Actions(处理异步操作)-----通过context的commit方法提交到------Mutations(可以被Devtools插件监听到)-----然后Mutate修改State中的数据

8.3 各个属性的作用

  1. state:它是vuex的状态定义存储的地方,vuex的任何状态都在这定义
  2. mutations:这是修改state中状态的唯一途径,任何修改操作都需要经过这
  3. actions:这是所有vuex异步操作的地方,只有在这执行完异步操作后,再通过context.commit()方法提交到mutations中才能把最终的结果给到state
  4. getters:这相当与vue的计算属性,在用户取得数据时如果还需对数据进行其它操作,可以在这里定义一个函数,把操作完的值return出去
  5. modules:这里是专门分模块的地方,可以把各个大型组件的状态分模块来管理,这样比较清晰明了

8.4 vuex代码演练

  1. vuex目录划分

    在这里插入图片描述

    modules:存放模块文件

    actions:存放actions对象

    getters:存放getters对象

    index:除了state对象不分离出来,其它的都分离出来

    mutations-types:定义各种方法名的常量

    mutation:存放mutation对象

  2. getters的使用

    export default {
        powerCounter(state) {
            return state.count * state.count;
        },
        //getters可以用来当计算属性使用
        get20Age(state) {
            return state.students.filter((student) => {
                return student.age > 20
            });
        },
        //在getters中还能使用getters中的其他值
        ageLength(state, getters) {
            return getters.get20Age.length;
        },
        //如果要传值,则要返回一个函数
        moreAgeStu(state) {
            return function (age) {
                return state.students.filter(stu => stu.age > age);
            }
        }
    }
    
  3. mutation的使用

    import {DECREMENT,INCREMENT} from './mutations-types';
    
    export default {
        //定义函数的方式可以用:[变量名](){}这样的方式定义
        [INCREMENT](state) {
            state.count++;
        },
        [DECREMENT](state) {
            state.count--;
        },
        incrementCount(state, num) {
            state.count += num;
        },
        addStudent(state,stu){
            state.students.push(stu);
        }
    }
    
  4. actions的使用

    import {
        INCREMENT
    } from './mutations-types';
    
    export default {
        /* outTimeCount(context){
            setTimeout(()=>{
                context.commit(INCREMENT);
            },2000);
        } */
        //上面的函数还可以这么写:
        outTimeCount(context) {
            return new Promise((resolve) => {
                setTimeout(() => {
                    context.commit(INCREMENT);
                    resolve('加一完成');
                }, 2000);
            });
        }
    }
    
  5. modules的使用

    import moduleA from './modules/moduleA';
    
    //用来划分模块
    modules: {
    	moduleA
    }
    
    //导出模块
    export default {
        state: {
            name: 'zhangsan'
        },
        mutations: {
            upName(state, newName) {
                state.name = newName;
            }
        },
        actions: {
            asyncUpdateName(context, newName) {
                setTimeout(() => {
                    context.commit('upName', newName);
                }, 2000);
            }
        },
        getters: {
            updateName(state, getters, rootState) {
                return state.name + rootState.count;
            }
        }
    
    }
    
  6. 前端vue代码

    <template>
      <div id="app">
        <h2>我是App组件</h2>
        <p>当前数量:{{$store.state.count}}</p>
        
        <!-- 测试getters  -->
        <h2>测试getters</h2>
        <p>count的平方:{{$store.getters.powerCounter}}</p>
        <p>获取年龄大于20的学生:{{$store.getters.get20Age}}</p>
        <table style="border:1px solid black;">
          <thead>
            <tr>
              <th>name</th>
              <th>id</th>
              <th>age</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="stu in $store.getters.get20Age" :key="stu.id">
              <td>{{stu.id}}</td>
              <td>{{stu.name}}</td>
              <td>{{stu.age}}</td>
            </tr>
          </tbody>
        </table>
        <p>年龄大于20的个数:{{$store.getters.ageLength}}</p>
        <p>返回年龄大于自定义参数的学生:{{$store.getters.moreAgeStu(19)}}</p>
        
        <!-- 加减操作:通过mutations实现数据更新 -->
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementCount(5)">+5</button>
        <button @click="incrementCount(10)">+10</button>
        <button @click="addStudent">添加学生</button>
        <button @click="outTimeCount">延迟2秒加一</button>
        <!-- HelloVuex组件 -->
        <hello-vuex></hello-vuex>
    
        <h2>测试modules代码</h2>
        <div>
          <h3>{{$store.state.moduleA.name}}</h3>
          <h3>{{$store.getters.updateName}}</h3>
          <button @click="asyncUpdateName">异步修改名字</button>
        </div>
        <!-- 
          vue的响应式的方法:
            vuex的初始化属性是会自动添加到vue响应式系统中的,但是如果我们后面手动的添加进去的属性,如果不用响应式的操作,会导致数据改变了,但是界面不会变
            Vue.set(数组/对象,下标/key,值);
            Vue.delete(数组/对象,下标/key);
         -->
      </div>
    </template>
    
    <script>
    import HelloVuex from './components/HelloVuex';
    import {DECREMENT,INCREMENT} from './store/mutations-types';
    
    export default {
      name: 'App',
      components: {
        HelloVuex
      },
      data() {
        return {
    
        }
      },
      methods: {
        increment(){
          this.$store.commit(INCREMENT);
        },
        decrement(){
          this.$store.commit(DECREMENT);
        },
        incrementCount(num){
          this.$store.commit('incrementCount',num);
        },
        addStudent(){
          let stu = {id:115,name:'陈建亮',age:25}
          this.$store.commit('addStudent',stu);
        },
        outTimeCount(){
          //this.$store.dispatch('outTimeCount');
          this.$store.dispatch('outTimeCount').then(msg=>{
            console.log(msg);
          });
        },
        asyncUpdateName(){
          this.$store.dispatch('asyncUpdateName','lisi');
        }
      },
    }
    </script>
    
    <style>
    
    </style>
    

九、项目准备

9.1 项目创建和git托管

使用vue-cli创建项目:vue create 项目名

使用码云托管代码(github没翻墙软件,太慢了所以没用):

​ 1.先在云端建立仓库

​ 2.使用vue-cli在本地初始化项目

​ 3.在本地项目中使用git init初始化项目

​ 3.复制码云仓库的地址,通过git remote add origin 仓库地址 关联远程仓库

​ 4.推送代码到远程仓库

9.2 引入css格式化文件

在github中可以下载到:normalize.css文件,然后导入app.vue中

<style>
  @import url('assets/css/normalize.css');
</style>

9.3 创建vue.config文件

vue.config文件中可以配置路径别名,就像vue中默认别名@代表src路径一样,本文件会在webpack打包时,跟已被脚手架隐藏的配置文件合并.

ps:在html标签或组件中使用别名时,需要在前面加上符号,如:assets/img/1.jpg

//vue.config
module.exports = {
    configureWebpack:{
        resolve:{
            alias:{
                'assets':'@/assets',
                'nerwork':'@/network',
                'utils':'@/utils',
                'components':'@/components',
                'views':'@/views'
            }
        }
    }
}

9.4 创建 .editorconfig 文件

.editorconfig文件是专门用来规定代码风格(如代码缩进,字符编码等)的配置文件,在团队开发时很有用,由于我没有团队,所以这个项目没有配置,但是在此做了记录,以防以后遇见不认识

t(){
this.KaTeX parse error: Expected 'EOF', got '}' at position 33: …EMENT); }̲, increm…store.commit(‘incrementCount’,num);
},
addStudent(){
let stu = {id:115,name:‘陈建亮’,age:25}
this.KaTeX parse error: Expected 'EOF', got '}' at position 40: …',stu); }̲, outTim…store.dispatch(‘outTimeCount’);
this.KaTeX parse error: Expected 'EOF', got '}' at position 93: … }); }̲, asyncU…store.dispatch(‘asyncUpdateName’,‘lisi’);
}
},
}




## 九、项目准备

### 9.1 项目创建和git托管

> 使用vue-cli创建项目:vue create 项目名

> 使用码云托管代码(github没翻墙软件,太慢了所以没用):
>
> ​	1.先在云端建立仓库
>
> ​	2.使用vue-cli在本地初始化项目
>
> ​	3.在本地项目中使用git init初始化项目
>
> ​	3.复制码云仓库的地址,通过git remote add origin 仓库地址 关联远程仓库
>
> ​	4.推送代码到远程仓库



### 9.2 引入css格式化文件

> 在github中可以下载到:normalize.css文件,然后导入app.vue中




### 9.3 创建vue.config文件

> vue.config文件中可以配置路径别名,就像vue中默认别名@代表src路径一样,本文件会在webpack打包时,跟已被脚手架隐藏的配置文件合并.
>
> ps:在html标签或组件中使用别名时,需要在前面加上~符号,如:~assets/img/1.jpg

```vue
//vue.config
module.exports = {
    configureWebpack:{
        resolve:{
            alias:{
                'assets':'@/assets',
                'nerwork':'@/network',
                'utils':'@/utils',
                'components':'@/components',
                'views':'@/views'
            }
        }
    }
}

9.4 创建 .editorconfig 文件

.editorconfig文件是专门用来规定代码风格(如代码缩进,字符编码等)的配置文件,在团队开发时很有用,由于我没有团队,所以这个项目没有配置,但是在此做了记录,以防以后遇见不认识

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 尚硅谷的Vue2笔记是学习Vue技术的好帮手。这份笔记详细地介绍了Vue的基本概念和使用方法,包括Vue的属性、指令、事件、计算属性、过滤器、组件等等。通过阅读这份笔记,我们可以了解Vue的整个生命周期,并且学习如何在Vue中绑定数据、响应事件、使用组件化等等。另外,笔记中也提到了Vue的MVVM模式、路由、状态管理、Ajax等进阶使用方法,以及Vue的一些注意点和优化技巧,这些非常实用且有助于深入学习和应用Vue技术。 总体来说,尚硅谷的Vue2笔记内容丰富、清晰易懂,适合初学者和中级开发者使用,是学习Vue技术的一份不错资料。需要注意的是,笔记中的代码及部分内容可能存在过时和不准确的情况,需要和Vue官方文档及其他权威资料进行比较和验证。 ### 回答2: 尚硅谷的Vue2笔记是一份非常全面和深入的Vue学习资料,它涵盖了Vue框架的基本概念和重要特性,包括Vue的组件化开发、指令、路由、Vuex状态管理、axios网络请求等。该笔记不仅注重理论知识的讲解,而且注重实战应用。它提供了大量的示例代码和练习项目,帮助学习者理解和掌握Vue的核心概念和技术。 在Vue2笔记中,作者从Vue的基本概念和MVVM架构模式开始讲解,然后逐步深入介绍了Vue的各种特性和用法,如组件、生命周期、计算属性、watch、事件处理、槽位、指令等等。特别是在组件化开发方面,作者详细介绍了组件之间的通信方式、props和$emit的使用、slot插槽的应用等等,这些都是Vue组件化开发中非常重要的概念。 除了组件化开发之外,Vue2笔记还详细介绍了Vue的路由、状态管理和网络请求等其他关键特性。在路由方面,作者讲解了Vue-Router的基本使用和路由守卫的应用,让学习者能够掌握Vue应用的页面导航和权限控制。在状态管理方面,作者讲解了Vuex的设计思想和使用方法,使学习者能够在复杂的应用中更好地管理和共享状态。在网络请求方面,作者介绍了axios库的使用和封装方法,帮助学习者更好地理解Vue应用中的数据请求和展示。 总的来说,尚硅谷Vue2笔记对于学习Vue框架的人来说是一份非常优秀的教材。它详细介绍了Vue的各个方面,并提供了丰富的练习项目,帮助学习者更好地掌握Vue的核心技术和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值