vue全家桶学习笔记
大纲核心成员vue:核心功能—插件,组件,数据管理,生命周期vue-router:路由机制—拆分,拆开,将文件划分大小vuex:vue官方提供的数据共享机制,全局性管理数据编译打包webpack:打包—js,css,图片,包的分隔,提供了很多开发功能vue-loader:转换器cli:脚手架,创建默认启动项目开发支持vue-devtools:按照组件查找后端渲染前端渲染...
大纲
核心成员
vue:核心功能—插件,组件,数据管理,生命周期
vue-router:路由机制—拆分,拆开,将文件划分大小
vuex:vue官方提供的数据共享机制,全局性管理数据
编译打包
webpack:打包—js,css,图片,包的分隔,提供了很多开发功能
vue-loader:转换器
cli:脚手架,创建默认启动项目
开发支持
vue-devtools:按照组件查找
后端渲染
前端渲染:性能更高,用户体验更好;所有的代码都需要用js写,所有的页面都需要被用户看到;
后端渲染:安全性高,SEO
结合:
vue-server-renderer:后端渲染的核心组件
nuxt.js:整合环境
UI组件
element-UI
vue-element-admin
Vue基础
历史介绍
angular 09年,复杂,学习曲线长,一开始被大家拒绝
react 13年,用户体验良好
vue 14年,用户体验良好,尤雨溪,无锡人
前端框架与库的区别
- jquery库 -> DOM(操作DOM) +请求
- art-template库 -> 模板引擎
- 框架 = 全方位功能齐全
- 简单的DOM体验 + 发请求 + 模板引擎 + 路由功能
- KFC的世界里,库就是一个小小的套餐,框架就是全家桶
- 代码上的不同
- 一般使用库的代码,是调用某个函数,我们自己把控库的代码
- 一般使用框架,其框架在帮助我们运行编写好的代码
- 框架:初始化一些行为
- 执行你所编写的代码
- 释放一些资源
- 框架:初始化一些行为
vue起步
-
引包
-
启动new Vue({el: 目的地,template:模板内容});
-
opations
- 目的地 el
- 数据源 data
- 模板 template
插值表达式({{}})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 数据绑定 -->
<!-- vue的模板语法 {{}} 双括号 -->
<h2>{{ name }}</h2> <!-- 绑定数据值 -->
<h3>{{ 1+1 }}</h3> <!-- 做运算 -->
<h4>{{ isTure }}</h4> <!-- 判断真假 -->
<h5>{{ str.split('').reverse().join('') }}</h5> <!-- 使用js中的方法 -->
<h1>{{ 1 > 2 ? '真' : '假' }}</h1> <!-- 使用三元表达式 -->
<h6>{{ {"name" : "张三"} }}</h6> <!-- 插入对象 -->
</div>
<script type="text/javascript">
// 2 创建实例化对象
var app = new Vue({
el: '#app', // el 挂载点,vue操作的对象
data: { // 数据属性
// 操作对象绑定的数据
// 既可以是一个对象,也可以是一个函数
name: '小陈',
hobby: '电子竞技', //data中数据发生改变,视图也会发生改变,简而言之,数据驱动视图
isTure: 1===1,
str: 'hello vue'
},
// 如果template中定义了内容 那么优先渲染 template 模板中的内容
// 如果没有定义内容,则加载的是#app中的模板
<!-- template: `<div>{{ hobby }}</div>` -->
template: ``
});
// 除了数据属性 vue 实例还暴露了一些有用的实例属性和方法
// 她们都有前缀$
console.log(app);
// 我们可以通过app.$数据名来获取vue实例中的数据
console.log(app.$data);
</script>
</body>
</html>
指令
- 在vue中提供了一些对于页面 + 数据的 跟为方便的输出,这些输出就成为指令,以v-xxx为例。
- 比如html中的属性
<div v-xxx></div>
- 比如html中的属性
- 在angular中以
ng-xxx
开头 - 在微信小程序中以
vx-xxx
开头 - 在vue中以
v-xxx
开头的就叫做指令 - 指令中封装了一些DOM行为,结合属性作为一个暗号,暗号有对应的值,根据不同的值,框架会进行相关的DOM操作的绑定
vue中常用的指令
-
v-text:元素的innerText属性,必须是双标签,跟{{}}效果是一样的,使用较少
-
v-html:元素的innerHtml
-
v-if :判断是否插入这个元素,相当于元素的销毁和创建
-
v-else-if
-
v-else
-
v-show:隐藏元素,如果元素确定要隐藏,会给元素的style加上
display:none
,是基于css样式的切换 -
v-bind:给标签进行属性绑定(类似于:hover–给元素添加属性)【简写 :bind】
-
v-on:绑定事件
- v-on:原生事件名 = ‘函数名’ 【简写 @】
-
v-for:遍历
- v-for = “(item, index) in 数组名/对象名” ----> 使用{{ itme.字段名 }}
v-text:只能在双标签中使用,其实就是给元素的innerText赋值 v-html:其实就是给元素的innerHTML赋值 v-if:如果值为false,不在页面上渲染,会留下<!---->作为标记,但是可视化界面上面没有显示,如果值为true就将值显示在可视化界面上面 v-if,v-else-if都有相对应的值,v-else直接写 v-show是控制DOM元素显示与否,true显示,false隐藏
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<style type="text/css">
.obj {
width: 200px;
height: 200px;
border: 1px solid;
}
.obj2 {
width: 200px;
height: 200px;
border: 1px solid;
}
.active {
background-color: aqua;
}
table{
/* 去掉表格中的横向 内部边框线 */
border-collapse: collapse; /* 表格单元格间距样式 */
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript">
// 2 创建实例化对象
new Vue({
el: '#app',
data: function() {
return {
msg: 'v-text指令',
msg2: '<i>斜体i标签</i>',
isShow: false,
isBlue: false,
isRed: false,
text: 'chenhaha',
listData: [
{id: 1, name: '小陈', sex: '女'},
{id: 2, name: '小王', sex: '女'},
{id: 3, name: '小姜', sex: '女'},
{id: 4, name: '小唐', sex: '女'},
{id: 5, name: '小黎', sex: '女'},
{id: 6, name: '小肖', sex: '女'}
],
person: {
name: '筱辰',
hobby: '街舞,rap,吉他',
age: 20
}
}
},
template: `
<div id="app">
// 通过text做数据的增加
<h2 v-text = "1 + 1"></h2>
<!-- 给标签添加text值 -->
<h3 v-text = "msg"></h3>
<!-- 给标签嵌套html标签innerHTML -->
<div v-html = "msg2"></div>
<!-- 根据条件的真假输出对应项的值 -->
<div v-if = 'isShow'>雨天,写作业</div>
<div v-if = '!isShow'>晴天,出去耍,晒太阳</div>
<div v-if = 'Math.random() > 0.5'>随机数大于0.5</div>
<div v-else>随机数小于0.5</div>
<!-- 根据属性值来让元素显示隐藏,实际上是改变display的值 none|block -->
<div v-show = 'isShow'>夏天</div>
<div v-show = '!isShow'>夏天</div>
<!-- v-bind 绑定class 通过属性值来让元素增加隐藏 -->
<div class = "obj" v-bind:class = "{active:!isBlue}" v-on:click = 'clickDiv'></div>
<!-- v-bind还可以绑定自定义属性 -->
<div v-bind:aaa = 'text'></div>
<!-- 遍历数组 -->
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
</tr>
<tr v-for = '(item, index) in listData'>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.sex }}</td>
</tr>
</table>
<!-- 遍历对象 -->
<ul>
<li v-for = "(value,key) in person">
{{ key }} -------> {{ value }}
</li>
</ul>
</div>
`,
methods: {
clickDiv(e) {
this.isBlue = !this.isBlue;
}
}
});
</script>
</body>
</html>
v-if和v-show的区别
v-if 是 “真正”的条件渲染,因为他会确保在切换过程中条件块内的事件监听器和子组件适当的被销毁和重建
v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——知道条件第一次变为真时,才开始渲染条件块。
相比之下,v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单的基于css进行切换。(导航栏)
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好。
vue的双向绑定(v-model)
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 单项数据绑定 -->
<span>单项数据绑定:</span>
<input type="text" :value="mag"/>
<hr />
<!-- 双向数据绑定 只会体现在UI控件上面 只能应用在value属性上 -->
<span>双向数据绑定:</span>
<input type="text" v-model="msg"/>
<h1>{{ msg }}</h1>
<hr />
<!-- 实际上就是一个 语法糖,它是v-bind:value v-on:input的体现 -->
<span>双向数据实现原理:</span>
<input type="text" v-bind:value="mfg" v-on:input="valueChange"/>
<h1>{{ mfg }}</h1>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
mag: "小猪佩奇",
msg: "好友记",
mfg: "肖申克的救赎"
}
},
methods: {
valueChange(e){
console.log(e.target.value);
this.mfg = e.target.value;
}
}
});
</script>
</body>
</html>
vue中的template(入口组件)
入口组件包含了:html,css,js
局部组件
打油诗:声子 挂子 用子
创建:(类似于自定义全局组件,使用时直接在父组件中,通过局部组件的声明名调用即可)
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 局部入口组件的的声明
var App = {
data() {
return {
}
},
// 局部入口组件的内容
template:
`
<h2>我是局部入口组件</h2>
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
全局组件
// 全局组件
// 第一个参数是组件的名字,第二个参数是组件的样式
Vue.component('V-button',{
template:
`
<button>按钮</button>
`
});
注意:在使用局部组件和全局组件时,不能单独使用,每个组件都是一个整体,在组件中使用全局组件和局部组件时,必须要写在组件的内部,它们是一个整体。
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 全局组件
// 第一个参数是组件的名字,第二个参数是组件的样式
Vue.component('V-button',{
template:
`
<button>按钮</button>
`
});
// 声子
var Rightcentent = {
data() {
return {
}
},
template:
`
<div>
<div>我是右边内容组件</div>
<V-button></V-button>
</div>
`
};
<!-- 侧边栏组件 -->
var Leftcentent = {
data() {
return {
}
},
template:
`
<div>我是左边菜单栏组件</div>
`
};
<!-- 头部组件 -->
var Header = {
data() {
return {
}
},
template:
`
<div>我是头部组件</div>
`
};
// 局部入口组件的的声明
var App = {
data() {
return {
}
},
template: <!-- 用子 注意:在使用创建的子组件是是一个整体,不能分散开来,不然只能显示第一个子组件的值-->
`
<div>
<Header></Header>
<div>
<Leftcentent></Leftcentent>
<Rightcentent></Rightcentent>
</div>
</div>
`,
<!-- 挂子 -->
components: {
Header,
Leftcentent,
Rightcentent
}
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
父组件往子组件中传值
1 先给父组件绑定自定义属性
2 在子组件中使用prop接收父组件传递的数据
3 只要使用props接收了数据之后,就可以在子组件中任意使用
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 声明全局组件 子组件
Vue.component('Child',{
template:
`
<div>
<p>我是孩子</p>
<input type="text" v-model="childData"/>
</div>
`,
<!-- 接收自定义属性 -->
props: ['childData']
});
<!-- 声明全局组件 父组件 -->
<!-- 1 先给父组件绑定自定义属性 -->
<!-- 2 在子组件中使用prop接收父组件传递的数据 -->
<!-- 3 只要使用props接收了数据之后,就可以在子组件中任意使用 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父组件中的数据'
}
},
template:
`
<div>
<p>我是父亲</p>
<!-- 在子组件中挂载自定义属性 -->
<Child :childData = 'msg'/>
</div>
`
});
// 声子
var App = {
template:
`
<div>
<Parent />
</div>
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
子组件往父组件中传值
1.在父组件中绑定自定义事件
2.在子组件中触发原生的事件,在函数中使用$emit触发自定义函数
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 声明全局组件 子组件
Vue.component('Child',{
template:
`
<div>
<p>我是孩子</p>
<input type="text" v-model="childData" @input="changeValue(childData)"/>
</div>
`,
<!-- 接收自定义属性 -->
props: ['childData'],
methods: {
changeValue(val){
<!-- 自定义的时间一定通过thi.$emit()去触发 -->
<!-- 在函数中使用$emit(自定义的事件名,传递的消息) -->
this.$emit('childHeader',val);
}
}
});
<!-- 1.在父组件中绑定自定义事件 -->
<!-- 2.在子组件中触发原生的事件,在函数中使用$emit触发自定义函数 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父组件中的数据'
}
},
template:
`
<div>
<p>我是父亲</p>
<!-- 在子组件中挂载自定义属性 -->
<Child :childData = 'msg' @childHeader = 'childHeader'/>
</div>
`,
methods: {
childHeader(val){
console.log(val);
}
}
});
// 声子
var App = {
template:
`
<div>
<Parent />
</div>
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
vue内置全局组件(插槽)
插槽:slot 插槽,作为承载分发内容的出口
<!DOCTYPE html>
<html lang="zh">
<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></title>
<style type="text/css">
.default {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.success {
color: #fff;
background-color: green;
border-color: #409eff;
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 通过插槽的方式封装全局组件
Vue.component('Vbtn', {
template: `
<button class = 'default' :class = 'type'>
<slot>
按钮
</slot>
</button>
`,
props: ['type']
});
<!-- 声子 -->
var Vcontent = {
template: `
<div>
我是内容组件
<Vbtn type = 'primary'>主要按钮</Vbtn>
<Vbtn type = 'success'>成功按钮</Vbtn>
</div>
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂子 -->
components: {
Vcontent <!-- 类似于App:App -->
},
<!-- 用子 -->
template: `
<Vcontent></Vcontent>
`
});
</script>
</body>
</html>
具名插槽(通过slot上的name)
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
Vue.component('myli',{
template:
`
<li>
预留的第一个空白
<slot name = 'two'></slot>
预留的第二个空白
<slot name = 'three'></slot>
</li>
`
})
var App = {
template:
`
<div>
<ul>
<myli>
<h2 slot = 'two'>我是第一个空白</h2>
<h2 slot = 'three'>我是第二个空白</h2>
</myli>
</ul>
</div>
`
}
<!-- 实例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: `<App></App>`
});
</script>
</body>
</html>
过滤器
过滤器的功能:就是为页面中的数据进行添油加醋的功能
过滤器的分类:
- 局部过滤器
- 全局过滤器
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 过滤器的功能:就是为页面中的数据进行添油加醋的功能
// 有两种:局部过滤器 全局过滤器
// 声明全局过滤器
Vue.filter('myReverse', function(value,arg) {
return arg + value.split('').reverse().join('');
});
var App = {
data() {
return {
price: 0,
msg: 'filter'
}
},
template:
`
<div>
<input type="number" v-model = 'price'/>
<!-- 使用局部过滤器 {{ 数据 | 过滤器名 }} -->
<h2>{{ price | myCurrentcy }}</h2>
<!-- 使用全局过滤器 -->
<h4>{{ msg | myReverse('I am going to study well you ') }}</h4>
</div>
`,
filters: {
<!-- 1 声明局部过滤器 -->
myCurrentcy: function(value) {
return "¥" + value;
}
}
}
<!-- 实例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: `<App></App>`
});
</script>
</body>
</html>
监视(watch)
watch监听的是单个属性。
基本的数据类型,简单监视。
复杂的数据类型深度监视。
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<h2>{{ msg }}</h2>
<button type="button" @click="stus[0].name = 'rose'">获取用户名</button>
<h4>{{ stus[0].name }}</h4>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
msg: '',
stus: [{name: 'jack'}]
}
},
watch: {
//简单监视
// 字符串
msg: function(newV, oldV) {
console.log(newV, oldV);
},
//深度监视
stus:{
deep: true,
handler:function(newV, oldV) {
console.log(newV, oldV);
console.log(newV[0].name);
}
}
}
})
</script>
</body>
</html>
计算属性
利用computed计算属性写网页版音乐播放器。
<!DOCTYPE html>
<html lang="zh">
<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></title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
ul{
list-style: none;
}
ul li {
margin: 20px 20px;
padding: 20px 20px;
}
.active{
background-color: aquamarine;
}
</style>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<audio :src='getCurrentSongSrc' autoplay="autoplay" controls="controls"></audio>
<ul>
<li v-for="(item,index) in musicData" @click="clickHander(index)" :class="{active:currentIndex == index}">
<h2>{{ item.id }} - 歌名:{{ item.name }}h2>
<p>歌曲来源:{{ item.sonSrc }}</p>
</li>
</ul>
</div>
<script type="text/javascript">
var musicData = [
{
id: 1,
name: '世界美好与你环环相扣',
author: '柏松',
sonSrc: 'music/世界美好与你环环相扣.mp3'
},
{
id: 2,
name: '昨天的你现在的未来',
author: '易烊千玺',
sonSrc: 'music/昨天的你现在的未来.mp3'
},
{
id: 3,
name: '精彩才刚刚开始',
author: '易烊千玺',
sonSrc: 'music/精彩才刚刚开始.mp3'
}
];
new Vue({
el: '#app',
data() {
return {
musicData:musicData,
currentIndex:0
}
},
computed:{
// 计算属性默认只有getter
// setter也可以
// 使用getter
// getCurrentSongSrc:function(){
// return this.musicData[this.currentIndex].sonSrc
// }
// 使用setter
getCurrentSongSrc:{
set: function(newV){
console.log(newV);
this.currentIndex = newV;
},
get:function(){
return this.musicData[this.currentIndex].sonSrc
}
}
},
methods:{
clickHander(index){
// 使用getter
// 直接修改数据的属性
// this.currentIndex = index;
// 使用setter
console.log(this.getCurrentSongSrc);
this.getCurrentSongSrc = index;
}
}
})
</script>
</body>
</html>
组件的生命周期
-
beforeCreate
- 组件创建之前
-
created
- 组件创建之后,就可以拿到自定义组件里面的内容
-
beforeMount
- 挂载数据到DOM之前会调用
-
mounted
- 挂载数据到DOM之后
-
beforeUpdate
- 在更新DOM之前调用该钩子,应用:可以获取原始的DOM
-
updated
-
在更新DOM之后调用该钩子,应用:可以获取原始的DOM
-
beforeDeatory
- 销毁数据之前
-
destroyed
- 销毁数据之后
-
activated
- 激活组件
-
deactivated
- 停用组件
<!DOCTYPE html> <html lang="zh"> <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></title> <script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"> <App></App> </div> <script type="text/javascript"> Vue.component('Test', { data() { return { msg: 'lorry' } }, template: ` <div> <h2>{{ msg }}</h2> <button @click = 'changerHanlder'>改变</button> </div> `, methods: { changerHanlder() { this.msg = this.msg + 'hello'; } }, beforeCreate: function() { <!-- 组件创建之前 --> console.log(this.msg); <!-- 打印输出undefined --> }, created: function() { <!-- 组件创建之后 --> console.log(this.msg); <!-- 打印输出lorry --> <!-- 使用该组件,就会调用created方法 --> <!-- 在created这个方法中可以操作后端的数据,数据驱动视图 --> <!-- 应用:发起ajax请求 --> }, beforeMount: function() { <!-- 挂载数据之前 --> <!-- 打印输出<div id="app"><app></app></div> --> console.log(document.getElementById('app')); }, mounted: function() { <!-- 挂载数据到DOM之后 Vue作用之后的DOM--> <!-- 打印输出<div id="app"><div class="app"><div><h2>lorry</h2></div></div></div> --> console.log(document.getElementById('app')); }, beforeUpdate: function() { <!-- 在更新Dom之前使用改方法 --> <!-- 打印输出 <div class="app"><div><h2>lorry</h2> <button>改变</button></div></div> --> console.log(document.getElementById('app').innerHTML); }, updated: function() { <!-- 在更新DOM之后使用该方法 --> <!-- 打印输出 <div class="app"><div><h2>lorryhello</h2> <button>改变</button></div></div> --> console.log(document.getElementById('app').innerHTML); }, beforeDeatory: function() { <!-- 销毁数据之前 --> console.log('beforeDeatory'); <!-- Test组件中内容的显示隐藏的时候,打印输出beforeDeatory --> }, destroyed: function() { <!-- 销毁数据之后 --> console.log('destroyed'); <!-- Test组件中内容的显示显示的时候,打印输出destroyed --> }, activated: function() { console.log('组件被激活了'); }, deactivated: function() { console.log('组件被停用了'); }, }); var App = { data() { return { isShow: true } }, template: ` <div class = "app"> <!-- <Test v-if = 'isShow'></Test> --> <!-- vue中的内置组件<keep-alive></keep-alive>,能在组件的切换过程中将所有的状态保存在内存中,重复渲染DOM --> <keep-alive> <Test v-if = 'isShow'></Test> </keep-alive> <!-- 根据按钮点击事件确定 Test组件中内容的显示隐藏--> <!-- 点击两次后,再次点击切换,后台会重新创建Test,然后再次调用beforeDeatory和destroyed --> <button @click = 'isShow = !isShow'>点击切换</button> </div> ` }; new Vue({ el: '#app', data() { return { } }, components: { App } }) </script> </body> </html>
keep-alive标签
在组件的切换过程中将所有的状态保存在内存中,重复渲染DOM(缓存)
keep-alive在路由中的使用
keep-alive保存加载过的数据,使用时直接调用,不用再次加载,节省项目运行时间,提高用户体验。
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var Timeline = {
template:
`
<div id = 'timeline'>
<h2>首页</h2>
</div>
`,
created() {
console.log('首页组件创建了');
},
mounted() {
console.log('首页组件DOM加载了');
},
destroyed() {
console.log('首页组件销毁了');
}
};
var Pins = {
template:
`
<div>
<h2 @click = 'clickHandle'>沸点</h2>
</div>
`,
methods: {
clickHandle(e) {
e.target.style.color = 'red';
}
},
created() {
console.log('沸点组件创建了');
},
mounted() {
console.log('沸点组件DOM加载了');
},
destroyed() {
console.log('沸点组件销毁了');
}
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/timeline',
component: Timeline
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 实例化app组件 -->
var App = {
template:
`
<div>
<!-- 动态路由路径 -->
<router-link to = '/timeline'>首页</router-link>
<router-link to = '/pins'>沸点</router-link>
<!-- 路由匹配组件的出口 -->
<!-- <router-view></router-view> -->
<!-- 使用keep-alive后,如果前面的数据缓存过后,就不会重新加载,直接调用 -->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
`
}
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router,
template: `<App></App>`,
<!-- 挂载组件 -->
components: {
App
}
})
</script>
</body>
</html>
vue组件的通信方式
vue组件之间通信可分为:
props和$emit(也就是常说的父子组件通信,常用)【父子组件中的传值】
父组件向子组件传递数据是通过props传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。
解决父子组件层数较少的情况
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script type="text/javascript">
/*
在下面的例子中,有父组件App和子组件Child。
1).父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;
2).子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。
*/
Vue.component('Child',{
data(){
return {
aaa:this.message
}
},
template:`
<div>
<input type="text" v-model="aaa" @input="passData(aaa)"/>
</div>
`,
props:['message'],
methods:{
passData(val){
// $emit(自定义事件名,传递的值)
this.$emit('getChildData',val);
}
}
});
var App = {
data(){
return {
msg:'我是父组件的内容'
}
},
methods:{
getChildData(val){
console.log(`我是子组件传进来的${val}`);
}
},
template:`<div>
<p>这是一个父组件</p>
<Child :message = 'msg' @getChildData = "getChildData"></Child>
</div>`
}
new Vue({
el:"#app",
data(){
return {
}
},
components:{
App
},
template:`<App />`
});
</script>
</body>
</html>
a t t r s ( 绑 定 属 性 ) 和 attrs(绑定属性)和 attrs(绑定属性)和listeners(监听) 【父子组件中的传值】
a t t r s 是 attrs是 attrs是pops的集合
解决多层组件之间的嵌套和传值方法
绑定事件,传值,然后通过事件来接收传递的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
$attrs和$listeners
第一种方式处理父子组件之间的数据传输有一个问题: 如果父组件A下面有子组件B, 组件B下面有组件C, 这时如果组件A想传递数据给组件C怎么办呢?
如果采用第一种方法, 我们必须让组件A通过prop传递消息给组件B, 组件B在通过prop传递消息给组件C; 要是组件A和组件C之间有更多的组件, 那采用这种方式就很复杂了。 Vue 2.4 开始提供了$attrs和$listeners来解决这个问题, 能够让组件A之间传递消息给组件C。
*/
Vue.component('C', {
data() {
return {
}
},
template: `
<div>
<div @click = 'cClickHandler'>{{$attrs.messagec}}</div>
</div>
`,
methods: {
cClickHandler(){
alert(1);
this.$emit('getCData','我是c的数据')
}
}
});
Vue.component('B', {
data() {
return {
}
},
template: `
<div>
<C v-bind="$attrs" v-on = '$listeners'></C>
</div>
`,
methods: {
}
});
Vue.component('A', {
data() {
return {
}
},
// props:['message'],
template: `
<div>
<B v-bind="$attrs" v-on = '$listeners'></B>
<!--<input type="text" v-model = '$attrs.messagec' />-->
</div>
`,
methods: {
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<p>这是一个父组件</p>
<A :messagec = 'messagec' v-on:getCData="getCData" ></A>
</div>`,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
};
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
</body>
</html>
中央事件总线(非父子组件间通信)(创建公共的类)
$on
绑定自定义事件,$emit
触发自定义事件
$on
和$emit
绑定同一个实例化对象
解决兄弟组件之间的传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。
*/
// 中央事件总线
var bus = new Vue();
Vue.component('brother2', {
data() {
return {
msg:"hello brother1"
}
},
template: `
<div>
<p>我是老大</p>
<input type="text" v-model = 'msg' @input = 'passData(msg)' />
</div>
`,
methods: {
passData(val){
// //触发全局事件globalEvent
bus.$emit('globalEvent',val)
}
}
});
Vue.component('brother1', {
data() {
return {
msg:"hello brother1",
brother2Msg:''
}
},
template: `
<div>
<p>我是老二</p>
<p>老大传递过来的数据:{{brother2Msg}}</p>
</div>
`,
mounted(){
// 绑定全局事件globalEvent事件,
bus.$on('globalEvent',(val)=>{
bus.brother2Msg = val;
})
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<brother1></brother1>
<brother2></brother2>
</div>`,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
}
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
</body>
</html>
provide(传值)和inject(接收)【父组件传值,子组件接收】
父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
msg:''
}
},
template:`
<div>我是孩子{{msg}}</div>
`,
inject:['for'],
created(){
// 拿到传递过来的值
this.msg = this.for;
}
});
Vue.component('Parent',{
template:`
<div>
<p>我是父亲</p>
<Child />
</div>
`
});
var App = {
data(){
return {
}
},
provide:{
for:'他爹'
},
template:`
<div>
<h2>我是入口组件</h2>
<Parent />
</div>
`
}
new Vue({
el:"#app",
template:`<App />`,
data(){
return {
}
},
components:{
App
}
});
</script>
</body>
</html>
p a r e n t 和 parent和 parent和children
挂载父组件,在子组件中通过props去接收
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child', {
props: {
value: String, //v-model会自动传递一个字段为value的prop属性
},
data() {
return {
// 将value 的值赋值给 mymessage
mymessage: this.value
}
},
methods: {
changeValue() {
console.log(this.mymessage);
this.$parent.message = this.mymessage; //通过如此调用可以改变父组件的值
console.log(this.$parent);
}
},
template: `
<div>
<input type="text" v-model="mymessage" @change="changeValue">
</div>
`
})
Vue.component('Parent',{
// 点击按钮,将mymessage的值传递给子组件
template:` <div >
<p>我是父亲组件{{message}}</p>
<button @click = "changeChildValue" > test < /button >
<Child ></Child>
</div>
`,
methods:{
changeChildValue(){
this.$children[0].mymessage = 'hello';
}
},
data(){
return {
message:'hello'
}
}
})
var App = {
data(){
return {
}
},
template:`
<div>
<h2>我是入口组件</h2>
<Parent />
</div>
`
}
var vm = new Vue({
el:'#app',
components:{
App
},
template:`
<App></App>
`
})
console.log(vm);
</script>
</body>
</html>
vuex流程图
Vuex原理
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
各模块之间的工作流程
- Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
- dispatch:操作行为触发方法,是唯一能执行action的方法。
- actions:操作行为处理模块,由组件中的
$store.dispatch('action 名称', data1)
来触发。然后由commit()来触发mutation的调用 , 间接更新 state。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。 - commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
- mutations:状态改变操作方法,由actions中的
commit('mutation 名称')
来触发。是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。 - state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
- getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。
Vuex与localStorage
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态, **具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果 localStorage里有保存的数据,取出来再替换store里的state。**
let defaultCity = "上海"
try { // 用户关闭了本地存储功能,此时在外层加个try...catch
if (!defaultCity){
defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
}
}catch(e){}
export default new Vuex.Store({
state: {
city: defaultCity
},
mutations: {
changeCity(state, city) {
state.city = city
try {
window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
// 数据改变的时候把数据拷贝一份保存到localStorage里面
} catch (e) {}
}
}
})
复制代码
这里需要注意的是:由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换:
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem("subscribeList")); // string -> array
在vue中获取DOM元素
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 组件的挂载
Vue.component('SubCom', {
template:
`
<div></div>
`
});
var App = {
template:
`
<div class = 'app'>
<button ref = 'btn'>按钮1</button>
<button ref = 'btn2'>按钮2</button>
<!-- 给组件绑定ref -->
<SubCom ref = 'abc'/>
</div>b
`,
created() {
<!-- 获取所有的加上有ref属性的集合 -->
console.log(this.$refs.btn);
},
beforeMount:function() {
<!-- 获取所有的加上有ref属性的集合 -->
console.log(this.$refs.btn);
},
mounted() {
<!-- 如果给标签蚌寺那个ref = 'xxx' 属性,使用this.$refs.xxx获取原生的js对象 -->
<!-- ref属性值不能重名 -->
console.log(this.$refs.btn);
console.log(this.$refs.btn2);
<!-- 如果是给自定义组件绑定ref属性,那么this.$refs.abc获取的是当前的组件对象 -->
console.log(this.$refs.abc);
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
给DOM元素添加事件的特殊情况
使用focus()方法,获取焦点事件
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var App = {
data() {
return {
isShow: false
}
},
template:
`
<div class = 'app'>
<input type = 'text' v-show = 'isShow' ref = 'input'/>
</div>
`,
mounted() {
this.isShow = true;
<!-- 能获取到input框,但是不能使用focus()方法 -->
console.log(this.$refs.input);
<!-- 在Dom更新 -->
<!-- $nextTick()方法,在DOM更新循环之后执行回调函数,再修改数据之后可以使用此方法,在回调函数中获取到更新之后的数据 -->
<!-- this.$ref.input.focus(); -->
this.$nextTick(function() {
console.log(this);
<!-- 窗体加载的时候input框默认触发焦点事件 -->
this.$refs.input.focus();
});
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
生命周期的图示
核心插件
路由
路由的实现
-
传统开发方式url改变后,立刻发生请求响应整个页面,有可能资源过多,传统开发会让页面出现白屏
-
前端路由的原理
<!DOCTYPE html> <html lang="zh"> <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></title> </head> <body> <a href="#/login">登录</a> <a href="#/register">注册</a> <div id="app"></div> <script type="text/javascript"> var oDiv = document.getElementById('app'); // onhashchange方法,哈希值改变后调用的方法 // a标签中href属性的值就是哈希值 window.onhashchange = function(){ // 访问到用户点击的哈希值 console.log(location.hash); // 根据哈希值来做相对应的处理 switch (location.hash){ case '#/login': oDiv.innerHTML = '<h2>我是登录页面</h2>' break; case '#/register': oDiv.innerHTML = '<h2>我是注册页面</h2>' break; default: break; } } </script> </body> </html>
-
SPA(Single Page Application) 单页面应用
- 锚点值改变
- 锚点值改变后,不会立刻发送请求,而是在某个合适的实际,发起的ajax请求页面的局部渲染
- 优点:页面不会立刻跳转,用户体验好
- Vue,Angular,React这些框架都是做单页面应用
- 锚点值改变
Vue-Router的基本使用
下载packag.json配置文件
npm init --yes
下载vue包
npm install vue --save
下载vue-router包
npm install vue-router -S
使用:
- 引包(两个全局组件 router-link to属性 router-view(匹配路由组件的出口))
- 创建实例化VueRouter对象
- 匹配路由规则
- 挂载new Vue()实例化对象中
- 给vue实例化对象挂在了两个对象 this.$router(),它就是VueRouter
- this.route()获取的是配置路由信息的对象
- 命名路由
- 绑定自定义属性 :to = “{name:‘路由的名字’}”
- 路由的参数
- path:‘/user/id’
- to:“{name:‘user’,params:{id: 1}}”
- path:‘/user’
- to:“{name:‘user’,query:{userId: 1}}”
- path:‘/user/id’
- 嵌套路由(应用于 子路由是不同的页面结构)
- /home/music ===> /home/movie
- 一个router-view中嵌套另外一个router-view
- /home/music ===> /home/movie
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var Login = {
template: `
<div>我是登陆页面</div>
`
};
var Register = {
template: `
<div>我是注册页面</div>
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/login",
component: Login
},
{
path: "/register",
component: Register
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
<div>
<!-- <a href="">登录页面</a> -->
<router-link to="/login">登录页面</router-link>
<router-link to="/register">注册页面</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
命名路由
绑定to属性,匹配路由对象(通过定义的name来使用)
routes中的path属于动态路由参数,以冒号开头
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var Login = {
template: `
<div>我是登陆页面</div>
`
};
var Register = {
template: `
<div>我是注册页面</div>
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/login",
name: "login", <!-- 给当前路由命名 -->
component: Login
},
{
path: "/register",
name: "register",
component: Register
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
<div>
<!-- <a href="">登录页面</a> -->
<!-- <router-link to="/login">登录页面</router-link> -->
<!-- 通过路由的命名来使用 -->
<router-link :to="{name: 'login'}">登录页面</router-link>
<!-- <router-link to="/register">注册页面</router-link> -->
<router-link :to="{name: 'register'}">登录页面</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
路由参数
路由范式(规则):
- xxx.html#/user/1
- 动态参数(params)路由
- ooo.html#/user?userId = 1
- ( ?)query查询
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var userParams = {
template: `
<div>我是用户1</div>
`,
created() {
<!--引入vue-router时就会抛出两个对象 -->
<!-- 这两个对象就挂载到Vue实例化对象 -->
console.log(this.$router);
console.log(this.$route);
<!-- 获取用户点击的id -->
<!-- 注意通过 :id传递了id参数参能获取到id的值 -->
console.log(this.$route.params.id);
}
};
var userQuery = {
template: `
<div>我是用户2</div>
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/user/:id",
<!-- params动态参数 -->
name: "userP", <!-- 给当前路由命名 -->
component: userParams
},
{
path: "/user",
<!-- query 查询 -->
name: "userQ",
component: userQuery
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
<div>
<!-- params:{key,value} -->
<!-- 动态路由路径 -->
<router-link :to="{name: 'userP', params:{id:1}}">用户1</router-link>
<router-link :to="{name: 'userQ', params:{userId:2}}">用户2</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
嵌套路由
菜单栏的动态切换,标题栏一样,通过小组件来实现页面的动态切换
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
<!-- 内层小组件 -->
var Song = {
template:
`
<div>歌曲列表</div>
`
};
var Movie = {
template:
`
<div>电影列表</div>
`
};
<!-- // 外层大组件 -->
<!-- 注意:每一个组件模板都是一个大的整体,需要在一个盒子里面 -->
var Home = {
template: `
<div>首页
<br />
<!-- 动态路由路径 -->
<router-link to = '/home/song'>歌曲</router-link>
<router-link to = '/home/movie'>电影</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/home",
<!-- params动态参数 -->
name: "home", <!-- 给当前路由命名 -->
component: Home,
<!-- 匹配多层目录下面的子目录 -->
children: [
{
path: "song",
<!-- params动态参数 -->
component: Song
},
{
path: "movie",
<!-- params动态参数 -->
component: Movie
},
]
}
]
});
<!-- // 声明组件 -->
var App = {
template: `
<div>
<!-- params:{key,value} -->
<!-- 动态路由路径 -->
<router-link :to="{name: 'home'}">首页</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
动态路由匹配
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 当前使用路由参数,列入/timeline/fronted导航到/timeline/backed,原来的组件实例会被复用,
// 因为两个路由都渲染同个组件,比起销毁在创建,复用则显得更高效,不过这也意味着组件的生命周期
// 不会再被调用
var ComDesc = {
data() {
return {
msg: ''
}
},
template:
`
<div>我是{{ msg }}</div>
`,
created() {
<!-- created方法只会走一次 -->
<!-- created可以发Ajax请求 -->
this.msg = '前端';
},
<!-- watch在当前组件内部监听路由信息的变化 -->
watch: {
'$route'(to,from) {
console.log(to); <!-- to就是一个routes对象 -->
console.log(from);
<!-- 发送ajax请求,获取到对应的参数 -->
this.msg = to.params.id;
}
}
};
var Timeline = {
template:
`
<div id = 'timeline'>
<!-- 动态路由路径 -->
<router-link :to = "{name: 'comDesc',params:{id: 'frontend'}}">前端</router-link>
<router-link :to = "{name: 'comDesc',params:{id: 'backed'}}">后端</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
};
var Pins = {
template:
`
<div>
<h2>沸点</h2>
</div>
`
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/timeline',
component: Timeline,
children: [
{
name: 'comDesc',
<!-- 动态路由的参数 以:开头 -->
path: '/timeline/:id',
component: ComDesc
}
]
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 实例化app组件 -->
var App = {
template:
`
<div>
<!-- 动态路由路径 -->
<router-link to = '/timeline'>首页</router-link>
<router-link to = '/pins'>沸点</router-link>
<!-- 路由匹配组件的出口 -->
<router-view></router-view>
</div>
`
}
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router,
template: `<App></App>`,
<!-- 挂载组件 -->
components: {
App
}
})
</script>
</body>
</html>
路由元信息(meta的使用及权限控制)
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<router-link to = '/home'>首页</router-link>
<router-link to = '/blog'>我的博客</router-link>
<router-link to = '/login'>登录</router-link>
<a href="javascript:void(0)">退出</a>
<!-- 每个路由组件都渲染到router-view里面了 -->
<router-view></router-view>
</div>
<script type="text/javascript">
Vue.use(VueRouter);
var Home = {
template:
`
<div>首页</div>
`
};
var Blog = {
template:
`
<div>我的博客</div>
`
};
var Login = {
data() {
return {
name: '',
pwd: ''
}
},
template:
`
<div>
<input type="text" v-model="name"/>
<input type="password" v-model="pwd"/>
<input type="button" value="登录" @click = 'loginHandle'/>
</div>
`,
methods: {
loginHandle() {
<!-- 登录 -->
<!-- 将用户名 密码保存下来 -->
localStorage.setItem('user', {name:this.name,pwd:this.pwd});
<!-- 跳转到博客页面 -->
<!-- 编程式导航 -->
this.$router.push({
name: 'blog'
})
}
}
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/blog',
name: 'blog',
component: Blog,
<!-- meta给未来的路由做权限控制 -->
meta: {
<!-- 证明用户访问该组件的时候需要登录 -->
auth: true
}
},
{
path: '/login',
component: Login
}
]
});
<!-- 全局路由匹配 -->
<!-- beforeEach会监测路由 -->
router.beforeEach((to, from, next) => {
console.log(to);
console.log(from);
if(to.meta.auth) { <!-- true -->
if (localStorage.getItem('user')) {
<!-- 如果localStorage有值则证明用户登录完成了 -->
next();
}else{
<!-- 用户需要登录 -->
next({
path: '/login'
});
}
} else {
<!-- false 直接放行 -->
<!-- 如果不调用 next() 方法会卡主页面-->
next();
}
});
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router, <!-- 挂载路由 -->
})
</script>
</body>
</html>
Vuex
Vue服务端渲染
Axios
Axios是一个基于promise的HTTP库,可以在浏览器和node.js中使用。
作用:
- 从浏览器中创建
XMLHttpRequests
- 从node.js创建
http
请求 - 支持
Promise
API - 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御
XSRF
攻击
参考文档链接:https://www.kancloud.cn/yunye/axios/234845
使用
安装
使用npm:
npm install axios
使用bower:
bower install axios
使用cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios的基本使用
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
template:
`
<div>
<button @click = 'sendAjax'>发请求</button>
</div>
`,
methods: {
sendAjax(){
this.$axios.get('http://127.0.0.1:8888/')
.then(res => {
<!-- 拿到statusText: "OK" -->
console.log(res.data.msg); <!-- 打印输出ok -->
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
处理并发请求
<!DOCTYPE html>
<html lang="zh">
<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></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
res1: '',
res2: ''
}
},
template: `
<div>
响应1: {{ res1 }},
响应2: {{ res2 }},
<button @click = 'sendAjax'>并发请求</button>
</div>
`,
methods: {
sendAjax() {
<!-- 请求1 get: /-->
<!-- 请求2 post :/add -->
<!-- 配置 -->
this.$axios.defaults.baseURL = `http://127.0.0.1:8888/`;
<!-- 发请求 -->
var r1 = this.$axios.get('');
var r2 = this.$axios.post('add','a = 1');
this.$axios.all([r1, r2])
.then(this.$axios.spread((res1,res2) => {
<!-- 请求全部成功 -->
this.res1 = res1.data;
this.res2 = res2.data;
}))
.catch(err => {
<!-- 有一个失败就失败了 -->
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
请求配置
这些是创建请求时可以用的配置选项。只有url
是必需的。如果没有指定method
,请求将使用替代get
方法。
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // 默认是 get
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // 默认的
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默认的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认的
},
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
// 如果设置为0,将不会 follow 任何重定向
maxRedirects: 5, // 默认的
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
proxy: {
host: '127.0.0.1',
port: 9000,
auth: : {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
请求拦截器interceptors
在请求或响应被then
或catch
处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
如果你想在以后可移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义axios实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
错误处理
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 请求已发出,但服务器响应的状态码不在 2xx 范围内
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
可以使用validateStatus
配置选项定义一个自定义HTTP状态码的错误范围。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 状态码在大于或等于500时才会 reject
}
})
取消
使用取消令牌取消请求
Axios的取消令牌API基于cancelable promises提议,它还处于第一阶段。
可以使用CancelToken.source
工厂方法创建cancel token,像这样:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
还可以通过传递一个executor函数到CancelToken
的构造函数来创建取消令牌:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
注意:可以使用同一个cancel token取消多个请求
<!DOCTYPE html>
<html lang="zh">
<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></title>
<style type="text/css">
.spinner {
margin: 100px auto;
width: 50px;
height: 60px;
text-align: center;
font-size: 10px;
}
.spinner>div {
background-color: #67CF22;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: stretchdelay 1.2s infinite ease-in-out;
animation: stretchdelay 1.2s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes stretchdelay {
0%,
40%,
100% {
-webkit-transform: scaleY(0.4)
}
20% {
-webkit-transform: scaleY(1.0)
}
}
@keyframes stretchdelay {
0%,
40%,
100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
</style>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
isShow: false
}
},
template: `
<div>
<div class="spinner" v-show = 'isShow'>
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
<button @click = 'sendAjax'>发请求</button>
</div>
`,
methods: {
sendAjax() {
<!-- 模拟类似cookie的机制 -->
<!-- 添加请求拦截器 -->
this.$axios.interceptors.request.use((config) => {
console.log(config);
var token = localStorage.setItem('token');
if (token) {
config.headers['token'] = token;
}
this.isShow = true;
return config;
}, function(err) {
return Promise.reject(err);
});
<!-- // 添加响应拦截器 -->
this.$axios.interceptors.response.use(response => {
<!-- // 对响应数据做点什么 -->
console.log(response);
this.isShow = false;
return response;
}, function(error) {
<!-- // 对响应错误做点什么 -->
return Promise.reject(error);
});
this.$axios.get('http://127.0.0.1:8888')
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
认识webpack
能完成所有常用的功能:
- 压缩
- 打包
- 多种文件的编译(比如less文件编译成css文件)
- 脚手架
- 生成
安装:
npm i webpack-cli -g
基本使用
index.js
//jquery存放在本地
import $ from './libs/jquery'; // 引入jquery
//jquery存放在node_modules
import $ from 'jquery';
$(function(){
alert(a);
})
webpack.config.js
model.exports{
//模式
mode: 'development',
//入口
entry: './src/js/index.js',
//输出
output: {
path: path.resolve(__dirname,'build'),
filename: 'build.js'
}
}
webpack是一个现代JavaScript应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fa7einSe-1585806966684)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200331142837324.png)]
历史介绍
- 2009年初,commonjs规范还未出来,此时前端开发人员编写的代码都是非模块化的,
- 那个时候开发人员经常需要十分留意文件加载顺序所带来的依赖问题
- 与此同时 nodejs开启了js全栈大门,而requirejs在国外也带动着前端逐步实现模块化
- 同时国内seajs也进行了大力推广
- AMD 规范 ,具体实现是requirejs define(‘模块id’,[模块依赖1,模块依赖2],function(){ return ;}) , ajax请求文件并加载
- Commonjs || CMD 规范seajs 淘宝玉伯
- commonjs和cmd非常相似的
- cmd require/module.exports
- commonjs是js在后端语言的规范: 模块、文件操作、操作系统底层
- CMD 仅仅是模块定义
- commonjs和cmd非常相似的
- UMD 通用模块定义,一种既能兼容amd也能兼容commonjs 也能兼容浏览器环境运行的万能代码
- npm/bower集中包管理的方式备受青睐,12年browserify/webpack诞生
- npm 是可以下载前后端的js代码475000个包
- bower 只能下载前端的js代码,bower 在下载bootstrap的时候会自动的下载jquery
- browserify 解决让require可以运行在浏览器,分析require的关系,组装代码
- webpack 打包工具,占市场主流
(function (root, factory) {
if (typeof exports === 'object') {
module.exports = factory(); //commonjs环境下能拿到返回值
} else if (typeof define === 'function' ) {
define(factory); //define(function(){return 'a'}) AMD
} else {
window.eventUtil = factory();
}
})(this, function() { //this相当于传的root
// module 返回给factory
return {
//具体模块代码
addEvent: function(el, type, handle) {
//...
},
removeEvent: function(el, type, handle) {
},
};
});
手动实现vue-cli脚手架工具,同时也学习webpack的使用
模块实现
1.下载webpack为项目开发依赖
npm install webpack@3.12.0 -D
安装全局webpack:
npm install webpack -g
2.创建main.js作为项目的入口文件
// 整个程序的入口文件
import Vue from './vue.js'
import App from './App.js'
// 模块整体加载
// import {num,num2,add} from './App.js'
// console.log(num);
// console.log(num2);
// add(3,5);
// import * as object from './App.js'
// console.log(object);
// console.log(object.num);
// console.log(object.num2);
// add(3,5);
new Vue({
el:'#app',
components:{
App
},
template:`<App />`
});
3.创建一个App.js
var App = {
template:`
<div>
我是一个入口组件
</div>
`
};
//1. 声明并导出
export var num = 2; //作为一整个对象key导出
//2. 声明再导出
var num2 = 4;
export {num2};
//3.抛出一个函数
export function add(x,y) {
return console.log(x+y);
}
//4.抛出一个对象
export default App;
4.在package.json文件中配置如下:
{
"name": "29_module",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"build": "webpack ./main.js ./build.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.12.0"
}
}
5.新建一个index.html,script脚本引入打包完成的build.js如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./build.js"></script>
</body>
</html>
webpack打包后文件的运行方式
- 直接运行build.js文件
- 配置build文件,然后通过run命令来运行打包后的build文件
3.上面那种方法也可以通过webpack直接运行
更多推荐
所有评论(0)