vue项目开发基本知识点总结

544 阅读23分钟

概要

1. 组件

2. 脚手架vue cli

3. vue的生命周期

4. vue路由 vue router

5. axios

6. vuex

1. 组件

1. 全局组件

语法:
  • 格式:
    Vue.component(tagName, options)
  • 参数:
    • tagName => 组件名称
    • options => 配置项
      • data => 数据,是个函数
      • template => 模板,内容为html结构(必须参数)
解析
  • 这里的Vue是一个对象,在引入的vue.js库中,每个Vue应用都是通过用Vue函数创建一个新的Vue实例开始的,这个Vue实际上就是一个构造函数。
  • 在Vue的构造函数(实例)中,它有一个component方法,Vue构造函数下面的这个component方法就是用来声明全局组件的。
  • 这个component方法接收两个参数,tagName(组件名称)和options(组件配置)。
  • tagName:当一个组件声明之后需要使用,使用的时候需要在html文件里面写标签对,而这标签对的名称,就是这个组件声明时候的名称。
  • options:针对这个组件我们需要给它很多设置。它是一个对象,可以放很多参数,最基本的有两个,一个是数据(data),一个是html模板(template)。

示例1:

全局组件的基本用法

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- 全局组件的名称(tagName) -->
    <counter></counter>
</div>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

/**
 * vue对象注册全局组件的方法
 * Vue.component(tagName, options)
 * 组件名称,配置项(data, template...)
 * 将组件名(tagName)放到html中
 * options是一个对象,表示组件中的选项
 */
Vue.component("counter",  {
    // template中所有的标签需要包含在一个父级当中
    template: '<button>按钮</button>',
});

// 实例化Vue对象
new Vue({
    // 用来放vue的容器,声明的这个vue对象,要在页面中放在id为app的div中展示。
    el: "#app",
});
示例2:

全局组件关联template

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <counter></counter>
</div>

<!--
    用来放vue模板的容器
    
    1. template标签它是放在body当中,并一定要与上面的div平级
    2. 需要给一个id用于关联
    3. 同样需要一个父级
-->
<template id="btn">
    <!-- 需要被包含在一个容器当中 -->
     <div>
     	<button>按钮</button>
     	<span>按照平常的html写法就可以了</span>
     </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js

// vue对象,调用component注册全局组件
Vue.component("counter",  {
    // 使用在body中vue模板(template)的id
    template: '#btn',
});

new Vue({
    el: "#app",
});
示例3:

全局组件关联中data的用法

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <counter></counter>
</div>

<!-- 用来放vue模板的容器 -->
<template id="btn">
     <div>
     	<button>按钮</button>
     	<!-- 在data中的数据可以使用模板字符串的形式使用 -->
     	<span>{{ count }}</span>
     </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js

// vue中component注册全局组件的方法中的参数options是一个对象,里面有若干属性和方法,data是其中一个表示组件中数据的方法
Vue.component("counter",  {
    template: '#btn',
    
    // 表示vue组件中的数据,是一个方法
    // 在es6中,在对象中写一个函数的方法
    data() {
        // 在data对象中需要有一个return,这个return是一个对象,在这个对象里面可以存储这个组件所需要的数据
        return{
            count: 0,
        }
    }
});

new Vue({
    el: "#app",
});
示例4:

全局组件中定义方法

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <counter></counter>
</div>

<!-- 用来放vue模板的容器 -->
<template id="btn">
     <div>
        <!-- 在vue中使用方法用 @事件名=“方法名” -->
     	<button @click="add">按钮</button>
     	<span>{{ count }}</span>
     </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js

Vue.component("counter",  {
    template: '#btn',
    
    data() {
        return{
            count: 0,
        }
    },
    
    // 在全局组件中定义方法
    methods: {
        add() {
            // 取到组件中的数据使用this.数据
    	    this.count++;
    	}
    }
});

new Vue({
    el: "#app",
});

注意:

  • 每个Vue应用都是通过用Vue函数创建一个新的Vue实例开始的。
  • 组件就是具体的一个个功能。一个实际的功能里面会有很多结构。结构都放在template中,就是一个模板。
  • template中所有的标签需要包含在一个父级当中。
  • 每一个全局组件之间相互独立,即每次实例化的Vue相互不关联。
  • 所有的组件名称不能使用驼峰命名(标签不能用大写字母),要使用-,比如说你的一个组件名称叫counterA,你在标签里面使用的话只能用



2. 局部组件

  • 语法:
    • 格式:
    new Vue({
        components: {
            tagName: options,
            tagName: options,
            ...
        }
    })
    
    • 注意:
      • 参数与全局组件一样
      • 全局组件是通过vue component生成的(没有s),局部组件用的是components(带s)。
解析
  • 局部组件相当于局部变量
  • 和原生一样,原生不建议使用全局变量,组件也是,尽量不使用全局组件。
  • 和全局组件不一样,全局组件是在原生的vue对象上使用component方法,Vue.component,而局部组件是new了一个Vue实例。
  • 这个被创建的vue实例放在components中,比注册全局组件的方法多了一个s。
  • 在components中的语法和全局组件中的语法一样。
  • 局部组件只能在当前实例的vue中使用。

示例1:

局部组件的基本用法

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- navBar组件 -->
    <!-- js中组件名定义的是驼峰命名,在标签中不允许驼峰,故用-连接 -->
    <nav-bar></nav-bar>
</div>

<!-- navBar组件的模板 -->
<navTemplate>
    <ul>
        <li>食材1</li>
        <li>食材2</li>
    </ul>
</navTemplate>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    // 局部组件直接在实例化后的vue中使用compontents,在这里可以放很多个组件
    components: {
        // 组件名
        navBar: {
            template: "#navTemplate",
        },
        // 组件名
        navList: {
            
        },
        // .....
    }
});
示例2:

在局部组件中存放数据,并定义方法

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- navBar组件 -->
    <nav-bar></nav-bar>
</div>

<!-- navBar组件的模板 -->
<navTemplate>
    <!-- 用模板字符串使用数据 -->
    <!--<ul>
        <li>{{ text[0] }}</li>
        <li>{{ text[1] }}</li>
    </ul>-->

    <!-- 使用v-for遍历 -->
    <ul>
        <li v-for="(item, index) in text" :key="index" @click="log">{{ item }}</li>
    </ul>
</navTemplate>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        // 组件名
        navBar: {
            // 定义模板
            template: "#navTemplate",
            
            // 数据
            data() {
                return {
                    text: ["食材1", "食材2"],
                }
            },
            
            // 方法
            methods: {
                log() {
                    console.log("点击");
                }
            }
        },
    }
});
示例3:

局部组件有作用域

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- navBar组件 -->
    <nav-bar></nav-bar>
    
    <!-- navList组件 -->
    <nav-list></nav-list>
</div>

<!-- 用来放vue的容器 -->
<!-- 局部组件无法应用,有作用域,只能在app中使用 -->
<div id="box">
  <!-- 组件模板2  -->
  <nav-list></nav-list>  
</div>

<!-- navBar组件的模板 -->
<navTemplate>
    <ul>
        <li>食材1</li>
        <li>食材2</li>
    </ul>
</navTemplate>

<!-- navList组件模板 -->
<template id="navListTemplate">
   <span>navList233333</span>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        // 组件名
        navBar: {
            // 定义模板
            template: "#navTemplate",
        },
        
        // 组件名
        navList: {
            template: "#navListTemplate",
        },
    }
});

new Vue({
    el: "#box",
});

关于全局组件和之间的区别

  • 全局组件和局部组件与js中的全局变量和局部变量非常相似,它们身上所具有的特性,在组件中也能够体现出来。



3. Props

定义:

props:在组件上定义一些属性用来传递数据(传递给组件里的结构使用)

语法:
  • 组件里:props:['属性名', '属性名', ...]
  • 模板里:{{ 属性名 }}
  • 标签里:<组件 属性名="值" 属性名="值"></组件>
解析
  • 用来传递数据
  • 和形参与实参差不多
  • html结构相同,但数据不同,组件传递数据

示例1:

props的基本用法

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- 每个li是一个组件,外面用ul包起来 -->
    <ul>
        <!-- boxList组件 -->
        <!-- 组件结构相同,数据不同,给每个组件的props中定义的属性赋值 -->
        <box-list title="可乐" price="112"></box-list>
        <box-list title="雪碧" price="333"></box-list>
    </ul>
</div>

<!-- boxList组件模板 -->
<template id="boxListTemplate">
    <li>
        <!-- 使用模板字符串的方式渲染props传递过来的值 -->
         <span>{{ title }}</span>
         <span>{{ price }}</span>
    </li>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        boxList: {
            template: "#boxListTemplate",
            
            // props 在组件上定义一些属性用来传递数据
            props: ["title", "price"]
        }
    }
});



3. Slot

定义:

slot:插槽

语法:
  • 插槽(slot):用于分发内容
    • template里定义:
    • 组件标签对里使用(标签对里的标签能被解析)
    • 注意:插槽只能写一个,多写会报错
  • 具名插槽:给slot添加name属性后就叫具名插槽
    • template里定义:
    • 组件标签对里使用:

解析
  • 在使用props传递数据的时候,在使用组件的标签对中,数据都当做属性传递进来。这种方法传递的数据比较少比较清楚,但数据量一多就显得累赘。
  • 在vue中,组件和标签是一样的,为了更像html标签,组件中传递数据可以用slot这种形式传递,结构会更清晰。
  • 举个例子,就像一台电脑,它有各种插槽用来放显卡,内存等等,还有usb接口等等,这些插槽,就相当于vue中的slot。
  • 在组件标签对中不会显示里面的标签,组件定义好之后,就相当于在内部已经成为一个完全封闭的状态了。

示例1:

slot的基本用法(传递数据)

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- boxList组件 -->
    <box-list>
        <!-- 组件标签对中的内容不显示 -->
        <!-- p标签中若有数据,使用slot分发内容,在组件的标签对里面放的都是数据 -->
    	<p>使用slot才能显示....</p>
    	<p>template里面使用一个slot就会全部显示</p>
    	...
    </box-list>
</div>

<!-- boxList组件模板 -->
<template id="boxListTemplate">
    <!-- 插槽在template中定义,相当于划一道口,想在哪里显示,slot插槽就放在哪里 -->
    <div>
        <h1>test</h1>
        
        <!-- 组件标签对中的内容在h1下面显示,它这里是显示组件标签对中所有的数据 -->
        <slot></slot>
    </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        boxList: {
            template: "#boxListTemplate",
        }
    }
});
示例2:

slot的基本用法(具名插槽)

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <!-- boxList组件 -->
    <box-list>
        <!-- 使用具名插槽 -->
        <span slot="cc1">插槽1</span>
	    <span slot="cc2">插槽2</span>
    </box-list>
</div>

<!-- boxList组件模板 -->
<template id="boxListTemplate">
    <!-- 插槽在template中定义,相当于每把刀上有一个名字,刀每划一道口,有特定的含义,使用的时候根据刀名字使用 -->
    <div>
        <h1>test</h1>
        
        <!-- 可以用名称定义显示部分(具名插槽) -->
	<slot name="cc1"></slot>
	<slot name="cc2"></slot>
    </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        boxList: {
            template: "#boxListTemplate",
        }
    }
});
示例3:

slot传递数据

html:

<!-- 用来放vue的容器 -->
<div id="app">
    <ul>
        <!-- boxList组件 -->
        <!-- 在组件标签对中使用具名插槽,并可以按照传统html写法把数据添加上去,一个标签对就是一个li,只要把组件模板中的插槽拿过来就可以了 -->
        <box-list>
            <span slot="title">可乐</span>
            <span slot="price">22</span>
        </box-list>
        <!-- boxList组件 -->
        <box-list>
            <span slot="title">雪碧</span>
            <span slot="price">33</span>
        </box-list>
    </ul>
</div>

<!-- boxList组件模板 -->
<template id="boxListTemplate">
    <!-- 在template中定义具名插槽,这里是具体的html结构,在li结构中 -->
     <li>
        <a href="#">
         	<slot name="title"></slot>
         	<slot name="price"></slot>
         	<span>食品介绍<span>
     	</a>
     </li>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    components: {
        boxList: {
            template: "#boxListTemplate",
        }
    }
});



4. 父子组件

4-1. 父子组件的定义
语法:
new Vue({
    // vue容器
    el: "#app",

    components: {
        父组件名: {
    	    template: "父组件template对应的id",
    	    
    	    data() {
    	        // 父组件数据
    	    },
    	    
    	    // 子组件
    	    components: {
    	    	子组件名: {
    	    	    template: "子组件template对应的id",
    	    	},
    	    	...
    	     }
        }
    }
});
解析:
  • 一个组件就是一个功能里面的结构,这个结构可能包含在其他的结构当中,而这个结构就是外面那个结构的子组件,包围子组件的那个结构就是父组件。
示例1:

基本的父子组件

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <!-- boxList组件(父组件) -->
   <box-list></box-list>
</div>

<!-- boxList组件(父组件)模板 -->
<!-- 父组件模板使用ul标签 -->
<template id="boxListTemplate">
     <ul>
        <!-- 在父组件中使用子组件 -->
        <!-- 子组件使用插槽 -->
     	<!-- 子组件只能在父组件模板里面调用 -->
     	<!-- 定义所有插槽的值(定义数据) -->
     	<item>
    		<span slot="title">可乐</span>
    		<span slot="price">44</span>
	    </item>
	    
     	<item>
    		<span slot="title">雪碧</span>
    		<span slot="price">33</span>
	    </item>
     </ul>
</template>

<!-- item组件(子组件)模板 -->
<!-- 子组件模板就是一个个li标签 -->
<template id="itemTemplate">
      <!-- html结构,值用插槽代替 -->
      <li>
        <a href="#">
         	<slot name="title"></slot>
         	<slot name="price"></slot>
         	<span>食品介绍<span>
     	</a>
     </li>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    // 父组件
    components: {
        boxList: {
            // 父组件模板
    	    template: "#boxListTemplate",
    	    
    	    // 子组件
    	    components: {
    	    	item: {
    	    	    // 子组件模板
    	    	    template: "#itemTemplate",
    	    	}
    	     }
        }
    }
});

关于组件间如何传递数据

  • 父组件向子组件传递数据(自动传)
    • 使用props属性传递数据
  • 子组件向父组件传递数据(主动传,事件触发)
    • 使用自定义事件

关于自定义事件

  • 在发数据组件的methods里定义一个方法,方法内容如下:this.$emit('event', value)
    • event:自定义事件名称
    • value:要传递的数据(可选参数)
  • 在发数据组件的标签里
    • <component @自定义事件名称="函数名"></component>
  • 在接收数据组件的methods里
函数名(val) {
    // val就是接收到的数据
}
4-2. 父组件给子组件传递数据
语法:
  • 父组件向子组件传递数据(自动传)
  • 使用props属性
解析
  • 父亲可以给儿子零花钱,即父组件可以给子组件传递数据,单向数据流
  • 在子组件标签里通过v-bind绑定一条属性,属性的值为父组件的数据名称
  • 在子组件里利用props属性把已经绑定的属性写进去
  • 在子组件的template里就可以使用数据了
示例1:

父组件给子组件传递数据(外->里)

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <!-- 父组件 -->
   <father></father>
</div>

<!-- father组件(父组件)模板 -->
<template id="fatherTemplate">
    <div>
        <h1>父组件</h1>
        <span>父组件的数据{{ name }}</span>
        <span>把"{{ name }}"传给子组件</span>
    
        <!--
            使用props传递数据给子组件
            1. 在子组件定义一个props用来接收父组件传递过来的数据,props是一个数据
            2. 在父组件中引用子组件,并给该子组件标签里通过v-bind绑定上在子组件上已经定义的props属性名
            3. 绑定的props属性名的值,就是父组件要传过来给子组件的值,这里是name,即取到父组件的数据名称name值
            4. 在子组件的template使用数据
        -->
        <!-- 子组件只能在父组件中调用 -->
        <son :fatherdata="name"></son>
    </div>
</template>

<!-- son组件(子组件)模板 -->
<template id="sonTemplate">
    <div>
        <h1>子组件</h1>
        <span>这是儿子</span>
        
        <!-- 此时已经将父组件的值通过props传过来了,要使用父组件中的值,就只需要使用在子组件中定义的props属性,并把定义的props属性名用模板字符串的方式在子组件模板中表现出来就行了 -->
        <!-- 父组件和子组件拥有独立的作用域,如果没有使用props绑定直接使用,会报错 -->
        <p>{{ fatherdata }}</p>
    </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    // 父组件
    components: {
        father: {
    	    template: "#fatherTemplate",
    	    
    	    // 父组件数据
    	    data() {
    	    	return {
    	    		name: "老王",
    	    		
    	    		// 用来存放子组件的数据
    	    		sonData: "",
    	    	}
    	    },

            // 子组件
    	    components: {
    	    	son: {
    	    	    template: "#sonTemplate",
    	    	    
    	    	    // 父组件向子组件传递数据,子组件需要定义一个props,用来接收父组件的数据
                    props: ['fatherdata'],
    	    	}
    	     }
        }
    }
});
4-3. 子组件给父组件传递数据
语法:
  • 子组件向父组件传递数据(主动传,事件触发)
// 在发数据组件的methods里定义一个方法
this.$emit('event', value)

...

// 在发数据组件的标签里
<component @自定义事件名称="函数名"></component>

...

// 在接收数据组件的methods里
函数名(val) {
    // val就是接收到的数据
}
解析
  • 儿子可以孝敬父亲,双向数据流。
示例1:

子组件向父组件传递数据((里->外))

html:

<!-- 用来放vue的容器 -->
<div id="app">
   <!-- 父组件 -->
   <father></father>
</div>

<!-- 父组件模板 -->
<template id="fatherTemplate">
     <div>
       	<h1>父组件</h1>
       	<span>子组件向父组件传数据</span>
       	
       	<!-- 使用子组件给父组件传递过来的数据,点击时候才会有 -->
       	<p>{{ sondata }}</p>

       <!-- getdata用来接收数据 -->
       <!-- 在发数据组件的标签里,使用自定义事件 -->
       <!-- 自定义事件等于事件的名字,这个函数名是用来接收数据的 -->
       	<son @getdata="getval"></son>
     </div>
</template>

<!-- 子组件模板 -->
<template id="sonTemplate">
  <div>
  	<h1>子组件</h1>
  	<span>这是子组件</span>
    <span>子组件要向父组件传数据</span>
  	

    <!-- 给父组件传数据 -->
    <button @click="send">给父组件传数据</button>
  </div>
</template>

<!-- js s -->
引入vue.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    // 父组件
    components: {
        father: {
            template: "#fatherTemplate",
            
            // 父组件数据
            data() {
                return {
                    // 父组件接收子组件传递过来的值
                    sondata: "",
                }
            },

            // 父组件方法
            methods: {
                // 在接收数据组件的methods里
                // 拿到子组件给父组件传递的值
                // 把刚刚接收过来的函数名定义一下
                getval(val) {
                    // 父组件的数据
                    this.sondata = val;
                }
            },

            // 子组件
            components: {
                son: {
                    template: "#sonTemplate",
                    
                    // 子组件数据
                    data () {
                        return {
                            // 要传给父组件的数据
                            message: "你好,我是小王~~~~~",
                        }
                    },
                    
                    methods: {
                        // 给父组件传数据,只能通过事件给父组件传数据(自定义事件)
                        // 在发数据的组件(子组件) 定义一个方法
                        send() {
                            // alert();
                            // 触发自定义事件
                            // $emit("事件名称", 传递的数据)
                            this.$emit("getdata",  this.message);
                        }
                    }
                }
            }
        }
    }
});


2. 脚手架vue cli

注意:

  • 脚手架是通过webpack搭建的一种vue开发环境

搭建脚手架步骤

  1. 安装nodejs之后,打开终端
  2. 使用npm install -g @vue/cli
  3. 创建项目
    • 把终端里的路径移到要创建项目的路径里
    • vue create 项目名称

vue相关常用命令介绍

  • Vue -V => 查看版本
  • Vue -h => 查看命令帮助
  • Vue -create => 创建一个项目
  • Vue -add => 增加一个插件
  • Vue -invoke => 在创建好的项目里调用插件
  • Vue -inspect => 检查webpack的配置
  • Vue -serve => 启动一个项目
  • Vue -build => 打包项目
  • Vue -ui => 打开ui库(少用)
  • Vue -init => 声明一个项目

脚手架目录及文件介绍

  • node_modules目录:表示nodejs里的模块
  • public目录:入口文件
    • 里面的index为模板文件,最终内容会渲染到这里面<div id="app">
    • favicon.icon:网页的icon
  • src:开发目录
    • assets目录:静态资源文件夹(图片、外部js、外部css、字体)
    • components目录:公用组件文件夹
    • views目录:非公用组件文件夹
    • App.vue:整个项目的根组件(主组件),所有组件都会被引入这里面,最终,这里面的组件会被渲染到public目录下的index.html里面
    • main.js:放js的逻辑处理,就是webpack打包的时候的入口文件,先进到这里对里面逻辑进行分析,看你引入了哪些东西,需要的东西都会在里面找到。
      • 里面有实例化Vue对象,在下面的new Vue({}).$mount("#app")其实就是new Vue({el: "#app"})
    • router.js:安装环境的时候的router,所有路由相关的信息都放在这里
    • store.js:安装环境的时候的vuex,用来存储数据(状态管理),集中管理数据,所有的数据在这个文件里面进行管理。
  • .gitignore:git版本控制忽略上传
  • babel.config.js:用来做babel(打包)的配置
  • package-lock.json:package.json锁,在安装的时候不下载新版本
  • package.json:webpack配置都在这里面
  • README.md:文档
  • vue.config.js:vue cli3配置文件

vue执行过程

  • App.vue是根组件,vue会默认把组件中的内容渲染到index中
  • 渲染到index中之后,接下来它会去找main.js,因为它是入口文件,其实index.html也会引入main.js,只是它最终不叫main.js,它变成了app.js,这是打包之后的
  • main.js中包含了整个项目的逻辑,如果页面需要路由或者vuex,都要在main.js里面引入(用es6的语法import)。
  • main.js引入了路由,页面它还需要其他的页面,其他的页面都放在路由当中引入。

关于引入

  • import .. from ...export default{}是es6中模块化的语法,export是用来导出,import是用来导入
  • 在vue中,一个功能或者一个页面,可以认为是一个组件,一个组件就可以认为是一个模块。
  • 我们在声明的时候,*.vue就是一个组件,即一个模块,在开发完之后,将他用export导出去,导出之后,在你需要用到的时候,直接导入进来
  • export是用来导出,举个例子
// 导出一个对象
export var kaivo = {...}

// 在需要用到的地方导入这个对象
import {kaivo} form "..."

或者另外一种形式

// 当他导入这个对象的时候,并没有加变量名,
// 直接导出对象
export {...}

// 这时候就不需要放在括号当中了,
// 这其实就是es6中对象的解构,去取其中的名字
import Vue from "vue"

vue组件

  • vue cli中*.vue这种文件就是组件

在脚手架里使用组件

创建一个MenuList模块,不使用router.js

  • MenuList.vue:相当于子组件

    <template>
      <li>
        <a href="#">
         	<slot name="title"></slot>
         	<slot name="price"></slot>
         	<span>食品介绍<span>
     	</a>
     </li>
    </template>
    
    <script>
        export default {
          name: 'Menu-list',
        }
    </script>
    
    <style scoped lang="less">
    
    </style>
    
  • app.vue:相当于父组件

    <template>
      <ul>
        <!-- 调用组件,使用插槽 -->
        <Menu-list>
            <span slot="title">可乐</span>
            <span slot="price">22</span>
        </Menu-list>
        <Menu-list>
            <span slot="title">雪碧</span>
            <span slot="price">33</span>
        </Menu-list>
      </ul>
    </template>
    
    <script>
        // 在一个组件里使用另一个组件,需要通过import导入
        import MenuList from './components/MenuList'
    
        // 但凡设置js都需要供出,相当于父组件
        export default {
            // 局部组件
            components: {
                // 子组件
                // 导入进来的组件要放在components中,
                // 在es6中如果key与value相同,就可以省略
                MenuList,
            }
        }
    </script>
    
    <style lang="less">
    
    </style>
    


3. vue的生命周期

vue生命周期图示

vue生命周期

vue生命周期详解

  • 开始之前,先new Vue,接下来它就需要去做一些初始化,初始化一些事件,以及初始化一个生命周期,这个生命周期里面有很多方法都需要初始化一下。接下来触发钩子函数。
  1. beforeCreate 创建实例前触发
    • 创建一个实例前就要被触发的,这时候实例并没有被创建。
    • 比如做一个预加载的loading,就可以放在这个钩子函数中了。
  • 当他触发完成之后,再次初始化,这时候初始化的是组件里的一些数据(data方法中),或者说是methods里面的事件等等,在这一步走完之后,这实例才算是被创建了。接下来触发钩子函数
  1. created 创建实例后触发
    • 这个钩子函数发生之后,这个实例就被创建完了,这个时候就可以使用数据和事件了,但是虽然实例创建完了,但在dom中还没有被创建,这时候页面中什么都没有
    • 在这里可以做,比如在后端请求数据,页面还没有展示,先请求数据,页面中dom创建完了,再把数据塞进去。
    • 在这时候可以把loading结束了。
    • 接下来开始渲染dom了
  • 先检查有没有el这个东西(vue的容器),如果没有,就会去找有没有vm.$mount(el),[要渲染dom的话首先要知道渲染到哪里,这是是要渲染到vue的容器里]
  • 然后去找有没有“template”这个属性,如果有的话,就会按照你给的这个“template”渲染,如果没有的话,就会安装"el"这个标签渲染,即直接把el标签渲染成dom元素,在这一步操作是在虚拟dom里面编译的,也就是说他做了很多事情,我们看不到,dom没有显示出来,这就是虚拟dom
  • 接下里触发钩子函数
  1. beforeMount 渲染dom前触发
    • 此时在虚拟dom中的模板,其实已经渲染完成了,接下来就是在真实的dom中渲染dom了
  • 接下来,在这个事件发生完成之后,就开始真正渲染dom了,这个时候,就会把el标签中的内容替换了,此时,页面中就有内容了,页面中就是一个真实的标签了。
  • 接下来触发钩子函数
  1. mounted 渲染dom后触发
    • 你如果需要在页面显示后去做一些事情,就在这个钩子函数中去处理。
  • 这个事件发生之后,接下来,并不是说这个东西显示出来就完事了,你的数据显示完成了,后面肯定需要去修改。
  • 如果这个数据有修改,那么在修改前它就会触发"beforeUpdate"钩子函数,在修改后又会触发"updated"钩子函数,这个修改也是在虚拟dom中修改的。
  • [虚拟dom]=> 为了提升页面性能
  • 虚拟dom会根据diff算法,和之前不一样才去渲染,一样的话就不会渲染,渲染完成触发"updated"钩子函数,触发之后,就到了后面的一个阶段(钩子函数)了,销毁阶段
  1. beforeUpdate 数据更改前后触发
  2. updated 数据更改后触发
  • dom已经渲染完成不需要修改了,这时候就需要销毁了,就会执行以下钩子函数。
  1. beforeDestroy 实例销毁前触发
  • 销毁中,清除数据,清除事件等等,有定时器的话,还要删掉定时器
  1. destroyed 实例销毁后触发
  • 这个钩子函数触发之后,整个组件的生命周期就接收了

注意:

  • 当new了一个vue的时候,生命周期就开始了,这里面的方法就是钩子函数
  • 总共有8个方法(事件)
  • new Vue就是实例化了vue对象


4. vue路由 vue router

路由:根据URL锚点路径,在容器中加载不同的模块

配置方式一

  1. 引入vue-router.js库
  2. 定义路由,并对应router配置参数
router: new VueRouter({
    routers: [
        {
            path: "路径",
            component: "此路径对应的组件名"
        }
    ]
});
  1. 使用<router-link>组件来导航,并通过to属性指定链接
  2. 定义路由出口:
    • <router-view></router-view>
示例:

路由配置方式一

html:

<div id="app">
    <!-- 使用路由 -->
    <!-- 它需要使用自己的标签进行跳转 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/news">新闻</router-link>
    <router-link to="/hot">热点</router-link>
    
    <!-- 需要指定一个地方去显示路由的内容 -->
    <!-- 给路由定义一个出口,而不是整个页面都显示,这就是单页应用(spa)的一个核心 -->
    <!-- 此时需要在点击首页路由的时候,在以下div中显示home组件中的路由 -->
    <div class="box">
        <router-view></router-view>
    </div>
</div>

<!-- js s -->
引入vue.js
引入router.js
...
<!-- js e -->

js:

new Vue({
    el: "#app",
    
    // 构造函数(实例化router对象)
    // 有若干与路由相关的参数
    router: new VueRouter({
        // 第一个参数是routers,它的值是一个数组,放所有的路由
        routers: [
            {
                // 路径
                // /表示根目录
                path: "/home",
                
                // 此路径对应的组件名,不带s,即只能放一个组件,即相当于一个页面
                component: {
                    template: "<h2>首页<h2>",
                }
            },
            {
                path: "/news",
                
                component: {
                    template: "<h2>新闻<h2>",
                }
            },
            {
                path: "/hot",
                
                component: {
                    template: "<h2>热点<h2>",
                }
            },
        ]
    }),
    
    // 创建实例前触发,钩子函数
    beforeCreate() {
        // 在创建实例前,将路由初始化到首页
        // 即每次刷新之后到首页
        this.$router.push("/home");
    }
});

配置方式二

  1. 引入vue-router.js库
  2. 定义(路由)组件
  3. 定义路由
  4. 创建router实例(路由对象),并对router配置参数
  5. 使用<router-link>组件来导航,并通过to属性指定链接
  6. 定义路由出口:<router-view></router-view>
示例:

路由配置方式二

html:

<!-- 热点模板 -->
<template id="hot">
    <h2>热点</h2>
</template>

<div id="app">
    <!-- 使用路由 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/news">新闻</router-link>
    <router-link to="/hot">热点</router-link>
    
    <div class="box">
        <router-view></router-view>
    </div>
</div>

<!-- js s -->
引入vue.js
引入router.js
...
<!-- js e -->

js:

// 定义路由的组件
const Home = {template: "<h2>首页</h2>"}
// 第二个方法,vue中用来注册组件的方法,是一个全局的方法
const News = Vue.extend({
    template: "<h2>新闻</h2>"
});
const Hot = {template: "#hot"}

// 定义路由
const routers = [
    {
        path: "/home",
        
        compontent: Home
    },
    {
        path: "/news",
        
        compontent: News
    },
    {
        path: "/hot",
        
        compontent: Hot
    }
],

// 创建router对象
const router = new VueRouter({
    // 把上面创建的路由对象放进来
    // 原来是routers: routers,es6里面可以简写成一个
    routers
});

// 接下来需要new一个vue,并把创建的路由对象放入实例化后的vue对象中
new Vue({
    el: "#app",
    
    // 上面创建的router对象
    router,
    
    /* 
    // 第一个路由重定向方法
    // 创建实例前触发,钩子函数
    beforeCreate() {
        // 在创建实例前,将路由初始化到首页
        // 即每次刷新之后到首页
        this.$router.push("/home");
    }
    */
});

// 第二个路由重定向方法
// router就是一个路由对象,可以直接调用
router.push('/home');

注意:

  • 路由的重定向:
    • this.$router.push("路径")
      • 其中this.$router为路由对象

嵌套路由

语法
{
    path: "父级路由地址", compontent: "父级路由组件", children: [
        {
            path: "子级路由地址", compontent: "子级路由组件"
        },
        ...
    ]
}
示例:

嵌套路由

html:

<div id="app">
    <!-- 使用路由 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/news">新闻</router-link>
    <router-link to="/hot">热点</router-link>
    
    <div class="box">
        <router-view></router-view>
    </div>
</div>

<!-- 热点模板 -->
<template id="hot">
    <h2>热点</h2>
    <ul>
        <li>
            // 二级路由对应的链接
            <router-link to="/hot/movie">电影</router-link>
        </li>
        <li>
            <router-link to="/hot/music">音乐</router-link>
        </li>
    </ul>
    
    <!-- 二级路由显示的地方 -->
    <div class="box">
        <router-view></router-view>
    </div>
</template>

<!-- hot子路由模板(二级路由对应的模板) -->
<template id="movie">
    <h2>电影</h2>
    <p>喜羊羊</p>
</template>

<template id="music">
    <h2>音乐</h2>
    <p>音乐111</p>
</template>

<!-- js s -->
引入vue.js
引入router.js
...
<!-- js e -->

js:

const Home = {template: "<h2>首页</h2>"};

const News = Vue.extend({
    template: "<h2>新闻</h2>"
});

const Hot = {template: "#hot"};

// hot子路由
const Movie = {template: "#movie"};
const Music = {template: "#music"};

const routers = [
    {path: "/home", compontent: Home},
    {path: "/news", compontent: News},
    {path: "/hot", compontent: Hot, children: [
        // 这里的path,不需要加 /
        {path: "movie", compontent: Movie},
        {path: "music", compontent: Music}
    ]}
],

const router = new VueRouter({
    routers
});

new Vue({
    el: "#app",
    
    router,
});

// 第二个路由重定向方法
// router就是一个路由对象,可以直接调用
router.push('/home');

动态路由匹配

示例:

动态路由匹配

html:

<div id="app">
    <ul>
        <li>
            <router-link to="/home">首页</router-link>
        </li>
        <li>
            <router-link to="/news">新闻</router-link>
        </li>
    </ul>
    
    // 路由出口
    <div class="box">
        <router-view></router-view>
    </div>
</div>

<!-- 新闻模板 -->
<template id="news">
    <span>新闻列表</span>
    <ul>
        <li>
            <router-link to="/news/1">新闻1</router-link>
        </li>
        <li>
            <router-link to="/news/2">新闻1</router-link>
        </li>
    </ul>
</template>

<!-- 新闻最终页模板 -->
<template id="new_list">
    <span>新闻最终页</span>
    <p>这是传递过来的参数(id):{{ this.$route.params }}</p>
</template>

<!-- js s -->
引入vue.js
引入router.js
...
<!-- js e -->

js:

const Home = {template: "<h2>首页</h2>"};
const News = {template: "#new"};

// 因为点击某个新闻要跳转到一个新的页面,所以也需要一个组件
const NewList {template: "#new_list"};

const routes = [
    {path: "/home", compontent: Home},
    {path: "/news", compontent: News},
    // 要匹配一个动态路由的话,就用:id,动态路径的参数
    // 这个设置完了之后,参数值会被设置到this.$route.params
    {path: "/news/:id", compontent: NewList},
]

const router = new VueRouter({
    routes
});

new Vue({
    el: "app",
    
    router,
});

router.push("/home");

脚手架里配置路由

示例:

脚手架里配置路由

main.js:如果npm安装了router会自动引入

import router from './router'

new Vue({
  router,
  ...
}).$mount('#app')

router.js

// 引入路由
import Home from './components/Home'
import Manage from './components/Manage'
import Order from './components/Order'
import Dishes from './components/Dishes'
import About from './components/about/About'

// 引入二级路由
import Intro from './components/about/Intro'
import Join from './components/about/Join'
import Contact from './components/about/Contact'

// 引入三级路由
import Wechat from './components/about/contact/Wechat'
import QQ from './components/about/contact/QQ'
import Email from './components/about/contact/Email'

Vue.use(Router)

const router = new Router({
  ...

  routes: [
    // 重定向(当用户输入一个错误的地址后跳转)
    {path: '*', redirect: "/home"},

    // 根目录
    {path: '/home', component: Home},
    {path: '/dishes',name: 'dishes',component: Dishes},
    {path: '/manage', component: Manage},
    {path: '/order', component: Order},
    {path: '/about', component: About,
        // 要展示的路由
        redirect: '/about/contact',  
        
        // 二级路由
        children: [
          // 要加父路由
          {path: '/about/intro', component: Intro},
          {path: '/about/join', component: Join},
          
          {path: '/about/contact', component: Contact, 
            // 要展示的路由
            redirect: '/about/contact/qq', 
            
            // 三级路由
            children: [
                {path: '/about/contact/wechat', component: Wechat},
                {path: '/about/contact/qq', component: QQ},
                {path: '/about/contact/email', component: Email},
          ]},
    ]},
  ]
})

Home.vue

一级目录

<template>
    <div>
        <h6>首页</h6>
        
        <router-link to="/home">首页</router-link>
        <router-link to="/manage">管理</router-link>
        <router-link to="/dishes">食品</router-link>
        <router-link to="/order">订单</router-link>
        <router-link to="/about">关于</router-link>
        
        <button @click="back">回退</button>
        <button @click="goTo">跳转</button>
    </div>
</template>

<script>
    export default {
        name: "home",

        methods: {
            back() {
                this.$router.go(-1);  // 回退
            },

            goTo() {
                this.$router.replace("/manage");
                this.$router.replace({name: 'dishes'});

                this.$router.push("/order");
            }
        }
    }
</script>

<style scoped>

</style>

Manage.vue

一级目录

<template>
    <div>管理</div>
</template>

<script>
    export default {
        name: "Manage",


    }
</script>

<style scoped lang="less">

</style>

Dishes.vue

一级目录,结构与上雷同,<div>食品</div>

Order.vue

一级目录,结构与上雷同,<div>订单</div>

  • about目录(有三级目录)
    • Intro组件
    • Join组件
    • Contact组件
      • Wechat
      • QQ
      • Email

About.vue

一级目录

<template>
    <div>
        <h6>关于我们</h6>

        <router-link to="/about/intro">简介</router-link>
        <router-link to="/about/join">加入</router-link>
        <router-link to="/about/contact">联系</router-link>
        <!--<nav>
            <ul>
                <li>
                    <router-link to="/about/intro">简介</router-link>
                </li>
                <li>
                    <router-link to="/about/join">加入</router-link>
                </li>
                <li>
                    <router-link to="/about/contact">联系</router-link>
                </li>
            </ul>
        </nav>-->

        <div class="box">
            <router-view />
        </div>
    </div>
</template>

<script>
    export default {
        name: "about"
    }
</script>

<style scoped lang="less">

</style>

Intro.vue

二级目录

<template>
    <div>简介</div>
</template>

<script>
    export default {
        name: "Intro"
    }
</script>

<style scoped lang="less">

</style>

Join.vue

二级目录,结构与上雷同,<div>加入</div>

Contact.vue

二级目录

<template>
    <div>
        <h2>联系我们</h2>

        <nav>
            <ul>
                <li>
                    <router-link to="/about/contact/wechat" tag="h3">微信</router-link>
                </li>
                <li>
                    <router-link to="/about/contact/qq" tag="h3">qq</router-link>
                </li>
                <li>
                    <router-link to="/about/contact/email" tag="h3">email</router-link>
                </li>
            </ul>
        </nav>

        <div class="box">
            <router-view />
        </div>
    </div>
</template>

<script>
    export default {
        name: "Contect"
    }
</script>

<style scoped lang="less">

</style>

Email.vue

三级目录

<template>
    <div>Email</div>
</template>

<script>
    export default {
        name: "Email"
    }
</script>

<style scoped lang="less">

</style>

QQ.vue

二级目录,结构与上雷同,<div>QQ</div>

Wechat.vue

二级目录,结构与上雷同,<div>微信</div>

路由其他知识点

1. 去掉导航里的#
解决方法

mode: "history"

示例:

router.js

...

export default = new Router({
    mode: 'hash',  // 去掉#用history
    
    ...
});
2. 指定激活的class
解决方法

mode: "linkActiveClass: "active"

示例:

router.js

...

export default = new Router({
    linkActiveClass: 'active',  // 选中默认样式
    
    ...
});

注意:

  • 如果此时home连接一直被选中,说明有一个bug。
  • 在router.js的home下有一个根目录{path: '/', component: Home},它没有一个自己的标识,所以没办法被判断。
  • 只要改成{path: '/home', component: Home}
  • 并且在链接上也改一下,<router-link to="/home">首页</router-link>
3. 指定跳转标签类型
解决方法

mode: "<router-link target="div"></router-link>"

示例:
<!-- 不需要a标签,指定一个跳转标签 -->
<router-link to="/manage" tag="span">管理</router-link>

/**
 * 就会被渲染成<span>管理</span>
 */
4. 用属性作为路由地址
解决方法

:to="属性名"
mode: "<router-link :to="homeLink"></router-link>"

示例:

根据数据绑定跳转

<!-- 此时不是定值,需要一个绑定属性,所以用v-bind -->
<router-link :to=orderLink>订单</router-link>

<script>
    export default {
        name: "...",

        // 是一个函数
        data () {
            return {
                orderLink: "/order",
            }
        }
    }
</script>
5. 给路由起名字
解决方法

{path: '/dishes',name: 'dishes',component: Dishes} :to="{name: 'dishes'}"

示例2:

根据路由名字跳转

router.js

...
{path: '/dishes',name: 'dishes',component: Dishes},
...

*.vue

<!-- 根据路由名字跳转 -->
<router-link :to="{name: 'dishes'}">食谱</router-link>
6. 路由跳转方法
  1. 回退
    • this.$router.go(-1);
  2. 跳转到指定路由
    • this.$router.replace("/manage");
    • 根据路由名字跳转
      • this.$router.replace(name: "dishes");
    • this.$router.push("/manage");
    • 根据路由名字跳转(常用)
      • this.$router.push(name: "dishes");
示例:

Home.vue

<template>
    <div>
        <h6>首页</h6>
        <button @click="back">回退</button>
        <button @click="goTo">跳转</button>
    </div>
</template>

<script>
    export default {
        name: "home",

        methods: {
            back() {
                this.$router.go(-1);  // 回退
            },

            goTo() {
                this.$router.replace("/manage");
                
                // 根据路由名字跳转
                this.$router.replace({name: 'dishes'});

                this.$router.push("/manage");
                
                // 根据路由名字跳转(常用)
                this.$router.push(name: "dishes
            }
        }
    }
</script>

<style scoped lang="less">

</style>
7. 错误路由的重定向
示例:

错误路由的重定向

router.js

...
// 重定向(当用户输入一个错误的地址后跳转)
{path: '*', redirect: "/home"},
...

路由守卫

1. 全局守卫(在所有路由展示前触发)
// 在引入router组件的页面中使用main.js
router.before.Each((to, from, next) => {
    // 即将要进入到的路由,值为路由
    to ...
    
    // 离开的路由(从哪个路由离开),值为路由
    from ...
    
    // 值为函数,这个函数决定你接下来要展示的路由页面
    next ...
})
示例:

全局守卫

router.js

...
const router = new Router({
    ...
});

// 全局守卫,点击路由就会触发
router.beforeEach((to, from, next) => {
  // 如果点击的是登陆的那个路由,直接跳转
  if (to.path == 'login') {
    // 如果是继续执行
    next();
  } else {  // 点击的不是登陆的路由,跳到登陆
    next("/login");
  }
});

export default router;
2. 后置钩子(在所有路由展示后触发)
// 在引入router组件的页面中使用main.js
router.after.Each((to, from) => {
    // 即将要进入到的路由,值为路由
    to ...
    
    // 离开的路由(从哪个路由离开),值为路由
    from ...
})
3. 路由独享守卫(在当前路由展示前触发)
// 在路由内部使用
beforeEnter(to, from, next) {
    // 即将要进入到的路由,值为路由
    to ...
    
    // 离开的路由(从哪个路由离开),值为路由
    from ...
    
    // 值为函数,这个函数决定你接下来要展示的路由页面
    next ...
}
3. 组件内的守卫
// 在路由组件内部使用
beforeRouterEnter(to, from, next) {
    // 在当前路由被展示前调用
    
    ...
}

beforeRouterUpdate(to, from, next) {
    // 在当前路由改变时调用
    
    ...
}

beforeRouterLeave(to, from, next) {
    // 在离开当前路由时调用
    
    ...
}


未完待续...

5. axios



6. vuex




~End~