渐进增强就是先兼容低版本 在逐渐地向高版本提高
优雅降级就是先完成高版本浏览器的编写 在向低版本兼容
加上这个属性标签就不能使用了
dom查找
dom新增创建
dom克隆删除属性操作
app分类
移动webapp 运行在移动端浏览器上的app
原生app :就是从移动端应用商店下载的app
混合式app:就是我们前端写好的页面(vue react html+css+js) 把我i们写的页面内嵌到原生项目中
就是把数组或者对象快速赋值的一个语法
墨刀 墨客 蓝湖
Vue
vue就是当下最流行的前端js框架(数据处理和数据绑定的一个工具)
是一个华人
前google员工
vue是一款用于构建用户界面的渐进式的自底向上增量开发的MVVM框架
渐进式:就是不做职责以外的事情.(就是vue可以在一个项目中的局部使用 他不会影响没有使用的位置 也可以整个项目都是用)
自底向上增量开发:先写好一个基础的页面 在去添加各个复杂的功能,简单到繁琐的过程
用来封装一些与业务(就是你写的项目的功能)无关的代码块 我们使用他进行拼装 即可完成指定项目功能
大大提高了开发效率(但是要学习新的语法对初学者来说比较麻烦)
是昨早的一种框架模式------》mvvm是mvc的变种
就是把一个项目一个功能抽象成了不同的模块 每个模块来管理自己的事情 让开发变得更加的简单
M (model)模型(今后只要说到模型大家自动转换成数据) 管理数据的
V (view) 视图 (就是用户可以看见的地方)
C (controller)控制器 用来对数据接收和展示的中间商
是vue中使用的一种模式
M (model)模型(今后只要说到模型大家自动转换成数据) 管理数据的
V (view) 视图 (就是用户可以看见的地方)
VM (ViewModel)视图模型 模型数据与视图中的一个数据桥梁(这个桥梁更加智能他能发现模型或者是视图中的数据改变 当一方发生了改变 就会立即通知另外一方进行改变)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjdKnjRD-1624408588808)(.\img\2.bmp)]
1.解决了数据绑定问题
2.可以开发大型单页面SPA应用
3.支持组件化
1.我们要使用先下载 :npm install -save vue
2.开始编写页面代码
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
{{text}}------{{num}}
div>
<script>
// 3.新建vm层 (就是vue实例)
new Vue({
// 4.关联模型与视图层
el:"#demoDiv",
data:{ //5模型层
text:"你好么么大",
num:18
}
})
script>
body>
html>
{{}}-----》模板语法 模板表达式 双花括号赋值法
作用:
用于在vue中解析表达式 (表达式 通过某种计算可以返回结果的一个公式)虽然在{{}}中可以来处理一些数据
但是在vue中不推荐在{{}}中写入太符复杂的逻辑(因为视图层就是显示的 你在里面处理太复杂的逻辑不合适)
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>模板语法h1>
<h1>{{text}}h1>
<h1>{{num}}h1>
<h1>{{bool}}h1>
<h1>{{arr[2]}}h1>
<h1>{{obj.age}}h1>
<hr>
<h1>{{updata.toUpperCase()}}h1>
<h1>{{updata.substr(1,3)}}h1>
<h1>{{arr.length}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"我是字符串",
num:666,
bool:true,
arr:[111,2222,3333,4444],
obj:{
name:"xixi",
age:18
},
updata:"abcdefg"
}
})
script>
body>
html>
vue中核心是允许我们使用简洁的模板语法进行声明式的数据渲染
声明式渲染:我们告诉程序我想干什么程序就会自动完成
命令式渲染:原生的都是命令时 我们需要告诉程序一步一步应该怎么走 他才会按照我们的指令前进
数据驱动
vue会时时刻刻的监控着模型和视图 当一方发生了改变另外一方也会随之发生改变
vue的双大括号中不要加双引号
什么式HTML的属性?
就是用来扩展HTML标签的功能
属性的语法?
写在HTML的开标签中 并且属性=“属性值”
vue的指令
指令是带有 v- 前缀的特殊属性 (就是在vue中带有v-前缀的 扩展HTML标签功能的一个技术)
vue指令的语法
写在HTML的开标签中 并且指令=“指令值” 注意:一个开始标签内可写入多个指令,多个指令间使用空格分隔
v-model 指令
作用:主要是用于表单上数据的双向绑定
语法:v-model = 变量
注:v-model 指令必须绑定在表单元素上
Vue框架核心的功能就是双向的数据绑定。 双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的
使用 v-model 指令来实现双向数据绑定 把视图数据与模型数据相互绑定
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-model指令h1>
<input type="text" v-model="inputval"/>
<h1>{{inputval}}h1>
<hr>
<input type="checkbox" v-model="bool"/>
<h1>{{bool?"你勾选了":"你没有勾选"}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
inputval:"",
bool:true
}
})
script>
body>
html>
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的
数据劫持:数据拦截 当我们访问或设置对象的属性的时候,都会触发Object.defineProperty()函数来拦截(劫持),然后在返回(get)或设置(set)对象的属性的值。并且当数据发生改变的时候做出反应。
发布者-订阅者模式:其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
v-show 指令
作用:控制切换一个元素的显示和隐藏
语法:v-show = 表达式
根据表达式结果的真假,确定是否显示当前元素
true表示显示该元素;false(默认)表示隐藏该元素
元素一直存在只是被动态设置了display:none
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-showh1>
<input type="checkbox" v-model="bool"/>{{bool?"显示":"取消"}}
<p v-show="bool">我要显示和隐藏p>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:true
}
})
script>
body>
html>
v-on 指令
作用:为 HTML 元素绑定事件监听
语法:v-on:事件名称=‘函数名称()’
简写语法:@事件名称=‘函数名称()’
注:函数定义在 methods 配置项中
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-onh1>
<button v-on:click="fun()">点我打印内容button>
<button @click="fun()">点我简写打印内容button>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
},
// 函数写在与data el同及位置使用methods包裹
methods:{
fun(){
console.warn("你好么么哒")
}
}
})
script>
body>
html>
v-for 指令
作用:遍历 data 中的数据,并在页面进行数据展示
语法:v-for = ‘(item, index) in arr’
item 表示每次遍历得到的元素
index 表示item的索引,可选参数
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-forh1>
<ul>
<li v-for="(v,i) in arr">{{v.name}}------{{v.age}}li>
ul>
<table border="1">
<tr v-for="(xiaoming,xiaohong) in arr">
<td>{{xiaohong}}td>
<td>{{xiaoming.name}}td>
<td>{{xiaoming.age}}td>
tr>
table>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
arr:[
{name:"xixi1",age:118},
{name:"xixi2",age:218},
{name:"xixi3",age:183},
{name:"xixi4",age:184},
{name:"xixi5",age:185},
{name:"xixi6",age:186}
]
}
})
script>
body>
html>
v-bind 指令
作用:给html的属性绑定变量
语法:v-bind:属性名 = ‘表达式’/ 简写 :属性名=‘表达式’
绑定一个属性:
绑定多个属性(不能使用简写):
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-bindh1>
<a v-bind:href="ahref">{{text}}a>
<a :href="ahref">11{{text}}11a>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"点我去百度",
ahref:"http://www.baidu.com"
}
})
script>
body>
html>
v-if v-else v-esle-if
v-if指令
作用:判断是否加载固定的内容
语法:v-if = 表达式
根据表达式结果的真假,确定是否显示当前元素
true表示加载该元素;false表示不加载该元素
元素的显示和隐藏 是对Dom元素进行添加和删除
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>v-ifh1>
<input type="checkbox" v-model="bool"/>
<p v-show="bool">我是v-show的元素p>
<p v-if="bool">我是v-if的元素p>
div>
<script>
new Vue({
el:"#demodiv",
data:{
bool:true
}
})
script>
body>
html>
首先两者在用户的角度效果一样 都是对元素在页面进行显示和隐藏的 接收数据布尔值 true显示 false隐藏
但是 v-if 是对DOM元素进行添加和删除已达到显示和隐藏 v-show是使用css进行的
应用场景:
v-show 在初始化的时候对电脑的资源消耗比较到 (对安全性相对较低的内容进行显示和隐藏)
v-if 是在切换的时候对电脑的资源消耗比较到 (对安全相对较高的内容进行显示和隐藏)
作用:必须配合v-if使用否则无效。当v-if条件不成立的时候执行
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>v-elseh1>
<h1 v-if="bool">我是if的内容h1>
<p>v-if与v-else之间不能有第三者p>
<h1 v-else>我是else的内容h1>
div>
<script>
new Vue({
el:"#demodiv",
data:{
bool:false
}
})
script>
body>
html>+
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>v-else-ifh1>
<select v-model="text">
<option value="吃饭">吃饭option>
<option value="睡觉">睡觉option>
<option value="在吃">在吃option>
<option value="在睡">在睡option>
<option value="上厕所">上厕所option>
select>
<p v-if="text=='吃饭'">用户选择了吃饭饭p>
<p v-else-if="text=='睡觉'">用户选择了睡觉觉p>
<p v-else-if="text=='在吃'">用户选择了在吃饭饭p>
<p v-else-if="text=='在睡'">用户选择了在睡觉觉p>
<p v-else-if="text=='上厕所'">用户选择了上厕所p>
<p v-else>用户什么都没有选择p>
div>
<script>
new Vue({
el:"#demodiv",
data:{
text:""
}
})
script>
body>
html>
v-text 指令
作用:操作网页元素中的纯文本内容。{{}}是他的另外一种写法 就是向网页中插入纯文本
v-text与{{}}等价,{{}}叫模板插值,v-text叫指令。
有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动
①使用v-text渲染数据
②使用{{}}语法渲染数据,但是同时使用v-cloak指令(用来保持在元素上直到关联实例结束时候进行编译),v-cloak要放在什么位置呢,v-cloak并不需要添加到每个标签,只要在el挂载的标签上添加就可以
v-html 指令
作用:双大括号会将数据解释为纯文本,而非 HTML 。为了输出真正的 HTML ,你需要使用 v-html 指令
语法:
v-once 指令
作用:当数据改变时,插值处的内容不会更新(会影响到该节点上的所有属性)
语法:
{{text}}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>v-htmlh1>
{{newhtml}}
<div v-html="newhtml">div>
<h1>v-once 一次性插值h1>
<input type="text" v-model="text">
<p>{{text}}p>
<p v-once>{{text}}p>
<p>{{text}}p>
<p>{{text}}p>
div>
<script>
new Vue({
el:"#demodiv",
data:{
newhtml:"我是字符串标签
",
text:"我是默认值"
}
})
script>
body>
html>
watch是用来监听data模型数据中的内容 当数据发生改变的时候 watch就会触发
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<input type="text" v-model="text">
div>
<script>
new Vue({
el:"#demodiv",
data:{
text:"我是默认值"
},
// 监听
watch:{
// 你要监听的数据:function(新值,旧值){
// 你要完成的逻辑
// }
text(newval,oldval){
console.log(`${newval}-----${oldval}`)
}
}
})
script>
body>
html>
概念:顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了 data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。
计算属性(computed) 是一个属性 所以与el methods等同级位置编写 它的主要作用是计算(计算data的数据 当data属性发生改变的时候他会知道 并且重新计算返回我们想要的结果 一条数据在不同位置展示出不同形态的时候)
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>为什么用计算属性 在模板中写太多的逻辑 会导致后期无法维护h1>
<p>{{text}}p>
<p>{{text.toUpperCase()}}p>
<p>{{text.toUpperCase().substr(1,3)}}p>
<h1>计算属性h1>
<p>{{newatext}}p>
<p>{{newbtext}}p>
div>
<script>
new Vue({
el:"#demodiv",
data:{
text:"abcdefghijk"
},
watch:{
},
// 计算属性
computed:{
// 需要返回的数据: function () {
// return 处理操作
// }
newatext(){
// 必须return
return this.text.toUpperCase()
},
newbtext(){
return this.text.toUpperCase().substr(1,4)
}
}
})
script>
body>
html>
为什么会造成这个想法
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<p>{{newtext}}p>
<p>{{showtext()}}p>
大家会发现两个的结果没有区别
div>
<script>
new Vue({
el:"#demodiv",
data:{
text:"abcdefg"
},
watch:{
},
methods:{
showtext(){
return this.text.toUpperCase()
}
},
computed:{
newtext(){
return this.text.toUpperCase()
}
}
})
script>
body>
html>
如果我们把计算属性调用多次 他只执行了一次
但是我们把方法调用多次 调用几次执行几次 有很大的资源浪费
区别:
计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
方法绑定数据只要被调用,方法将总会再次执行函数。
计算属性相对于方法在处理特定场合下节省资源性能
计算属性与侦听器的区别:
当watch监听的值发生改变就会被调用,watch可以在数据变化时做一些异步处理或者开销大的操作
计算属性是计算依赖的值,当依赖的值发生改变才会触发。
事件对象就是用于描述触发这个事件的元素信息
$event
v-on指令提供了事件修饰符来处理DOM事件细节
按键修饰符: .up, .down, .ctrl, .enter, .space等等
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<input type="text" @keydown.ctrl="fun()">
div>
<script>
new Vue({
el:"#demodiv",
data:{
},
methods:{
fun(){
console.log("aaaaaaaaaa")
}
},
watch:{
}
})
script>
body>
html>
【扩展】事件修饰符
prevent修饰符:阻止事件的默认行为(submit提交表单)
stop修饰符:阻止事件冒泡
capture修饰符:与事件冒泡的方向相反,事件捕获由外到内
self:只会触发自己范围内的事件,不包含子元素
once:只会触发一次
注意:修饰符可以串联使用
vue请求数据有Vue-resource、Axios、fetch三种方式。Vue-resource是Vue官方提供的插件,axios是第三方插件,fetch es6原生
Vue-resource在vue2.0的时候已经停止更新了
axios是对XHR对象使用promise进行了二次封装简化了语法
fetch是es原生(react中会带大家写)
axios 是一个第三方的数据请求库 使用promise对XHR对象进行了封装 是现今最主流的一种数据请求方式
使用先下载
npm install --save axios
axios封装
生命周期 就是vue实例从创建到销毁的过程
钩子函数:本质是一个函数 但是他是一个会被自动调用的函数
生命周期的钩子函数:就是vue从创建到销毁的过程中被自动调用的函数(可以帮助我们在vue中完成一些特定条件下的自动执行的业务)
生命周期的钩子:
beforeCreate(创建实例)
created(创建完成)
beforeMount(开始创建模板)
mounted(创建完成)
beforeUpdate(开始更新)
updated(更新完成)
beforeDestroy(开始销毁)
destroyed(销毁完成)
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
<h1>{{text}}h1>
<button @click="text='我被改了'">点我更新button>
div>
<script>
new Vue({
el:"#demodiv",
data:{
text:"我是一个字符串"
},
methods:{
},
watch:{
},
computed:{
},
// 生命周期
// **beforeCreate(创建实例)**
// **created(创建完成)**
// **beforeMount(开始创建模板)**
// **mounted(创建完成)**
// **beforeUpdate(开始更新)**
// **updated(更新完成)**
// **beforeDestroy(开始销毁)**
// **destroyed(销毁完成)**
beforeCreate(){
console.log("创建实例")
},
created(){
console.log("实例创建完成")
},
beforeMount(){
console.log("开始创建模板")
},
mounted(){
console.log("创建完成")
},
beforeUpdate(){
console.log("开始更新")
},
updated(){
console.log("更新完成")
},
beforeDestroy(){
console.log("开始销毁")
},
destroyed(){
console.log("销毁完成")
},
})
script>
body>
html>
过滤器作用
在不改变数据的情况下,输出前端需要的格式数据
坑 :面试的时候 面试官或者今后与同事沟通的时候可能会被 问道 你能给我说下vue中的内置过滤器吗?
2.0中已经废弃了内置过滤器,需要我们自定义过滤器来使用filter
全局过滤器定义的内容在页面中的所有实例中都可以使用
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
{{text|xiaoming}}
div>
<div id="demodivb">
{{text|xiaoming}}
div>
<script>
// 如果数据在页面展示的时候和我们的续期想法不一样我们可以使用过滤器格式化展示数据
// 全局过滤器定义在实例之前
Vue.filter("xiaoming",(val)=>{
// 大于5个就保留5位 并且在后面加...
if(val.length>=5){
return val.substr(0,5)+"..."
}else{
return val
}
})
new Vue({
el:"#demodiv",
data:{
text:"我是第一个内容哦么么哒"
}
})
// =====================
new Vue({
el:"#demodivb",
data:{
text:"呵呵哒呵呵哒"
}
})
script>
body>
html>
只能在指定实例中使用
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.min.js">script>
head>
<body>
<div id="demodiv">
{{text|xiaohone}}
div>
<div id="demodivb">
{{text|xiaohone}}
div>
<script>
// 局部过滤器 写在指定实例当中 与data等同级
new Vue({
el:"#demodiv",
data:{
text:"西游记"
},
filters:{
xiaohone(val){
return "<<"+val+">>"
}
}
})
new Vue({
el:"#demodivb",
data:{
text:"红楼梦"
}
})
script>
body>
html>
总结:
在没有冲突的前提下,过滤器可以串联
电脑上必须要有node
安装淘宝镜像 cnpm (非必装,网络慢的情况可安装)
npm install -g cnpm --registry=https://registry.npm.taobao.org
如果安装过程中报错 请您连你手机的wifi
1 全局安装vue-cli npm install -g @vue/cli (除了你电脑重装系统或者是重装了node以外 就不用在安装了)
2.查看版本 vue --version
3.开始创建项目 但是需要先把你的cmd路径切换到你想创建项目的文件夹下 vue create 项目名
在弹出的选择中 选择第三项 剩下的眼睛闭上一路回车
4 cd到项目名下
5 npm run serve启动
因为空脚手架中有很多与我们开发没有关系的内容 所以拿到脚手架在写我们的代码之前 需要删除一些默认的内容
1.删除components文件夹中的HelloWord.vue
2.进入到app.vue(是所有组件的老大所有的组件今后要显示都要关联到app.vue中 写在app中的内容在所有地方都会显示)
保留如下内容:
以.vue结尾的文件就是单文件组件
在一个.vue文件中分为三部分 template是写html script 是写js的 style是写css的
我们之前学的 data methods watch computed filters 以及8个钩子 除了data的语法变了 剩下没有任何改变
组件:用来封装可以复用的ui代码块
模块:用来封装可以复用的js代码块
组件:用来封装可以复用的ui代码块
本质:组件的本质是自定义标签
1.提高开发效率
2.降低测试难度
在所有地方都可以使用的组件
如果要使用
在main.js中引用 调用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 1.全局组件的引用
import Bb from "@/components/bottombar.vue"
// 2.全局组件调用
// Vue.component("组件名",你要使用的组件)
Vue.component("Bb",Bb)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
之后在任何位置直接使用
1.在components文件夹下创建 以.vue结尾的文件
2.在其中写入 template script style (每次都写很麻烦 所以快速创建方式是vscode中 大家会发现什么都没有显示 原因是因为没有在app中建立关系 3.要把我们的组件和app建立关系 (1)引用 (2)调用 局部组件使用components来进行表示 写在与el data methods等同级的位置 (3)使用 data methods watch computed filters 八个钩子 组件中的属性(后面还有内容) data的使用 思考?为什么组件的data是一个函数 而原来的写法确是一个对象? 课下自行百度 其他属性语法以及使用没有任何变化 在组件的style范围内来写样式 但是默认情况下一个组件写的样式会影响其他组件 为了解决这个问题 所以我们需要给样式的范围添加一个scoped当前样式仅对当前组件生效 就是vue组件与组件之间的嵌套关系 我们就可以非常方便的使用这种嵌套关系来进行页面内容的 拼装 从而减少组件的体积 父组件能直接使用子组件的数据吗? 不能 子组件能直接使用父组件的数据吗?不能 vue中组件与组件之间是一个完整的 独立的个体 他们之间的数据默认情况下是绝对不能相互使用的 既然默认不行 那么有没有办法可以呢? 父组件把数据给子组件 props 是vue的一个属性 写在与data methods等同级的位置 props的作用就是用于接收组件外部传递进来的数据 props:[“接收参数1”,“接收参数2”,…“接收参数n”] 使用: 1.在子组件中设置props的接收参数 2.在页面内想使用的地方把props的数据插入页面 3.父组件开始传递 在子组件被调用的地方进行传递 总结下基本props的使用 props就是标签的属性 就是对父组件传递过来的数据进行校验 (数据类型 是否为空 默认值) props:{ //对象 } 为什么写的有问题 但是props验证没有错误提示? 子组件把数据给父组件 默认是不被允许的 必须要通过自定义事件来进行传递 使用: 子组件中: 1.在页面中创建一个事件 调用一个函数 2.在函数中使用this.$emit进行自定义事件的创建 父组件: 1.在子组件被调用的地方 使用 @/v-on:自定义事件名=“当前父组件的函数(不要圆括号不要圆括号)” 2.创建那个父组件的函数 函数中形参就是子组件传递过来的数据 内置别名 @ 看见这个@就是src文件夹 (无论在那个层级中只要写了@ 那么就是src文件夹) 自定义别名 在vue脚手架中默认给我们提供了一个@=src的一个文件夹别名 但是呢不够用比如我们要找到components这个类路径怎么办? 配置: 在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下 在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下 在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下 在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下在项目的根路径下 创建一个vue.config.js(名字不能变)的文件 在其中使用 module.exports={}进行暴漏 千万不要忘了重启项目 因为修改了配置文件必须重启项目 插槽/槽口 引子: 如果我把组件的调用写成双标签 并且在开标前和关标签中写入内容 会显示吗? 不会 1.基本使用 就是你在想接受外部插入的内容组件之上放置一个slot组件 问题: 刚才直插入了可以一个 多个呢? 可以插入的 但是一个开口插入多个内容 后期如何管理? 带有名字的槽口 slot 在定义slot的时候 使用name属性起个名字 插入的时候 给元素使用slot属性=“slot的名字” 问题 有啥用? 很多使用slot和props有相似点 props在 一个组件被多次调用 但是内容不同数量相同的时候使用 slot 在 一个组件被多次调用 但是内容不同数量也不相同的时候使用 可以搭建spa(单页面应用) 的一个技术 让我们的项目可以进行页面的切换 特点与原理 利用锚点完成切换 流程 :就是在vue create 新建项目的时候 选中Router项即可 在src文件夹下多了一个router的文件夹与views的文件夹 router文件夹 就是配置路由的文件夹 views就是写路由页面的文件夹 1.在views下创建你新建的路由页面组件 2.配置路由规则在router文件夹下的index.js中去先引用在配置 3.需要去创建路由出口(自动创建的时候会给我们自动添加) 路由出口就是 我们的路由最终要在那里显示 4.设置路由导航 传统的跳转连接我们使用a标签 但是但是但是在vue中千万不要使用a标签哦!!!!!!! 要跳转使用 router-link 就是进行路由页面的跳转连接 1.下载vue-router库 : npm install --save vue-router 2.创建路由组件页面 就是在views文件夹下创建哪些.vue文件 3.配置路由规则 在router文件夹下的index.js文件中进行先引用在配置 4.实例化路由对象并且传入路由规则 5 把路由实例在main.js中传入vue实例中建立关系 6.设置出口 router-view 7.设置导航 router-link 路由导航就是切换路由的呢些方式 1.html方式:a标签 2.js方式:href replace() go(正数负数) forword() back() 1.标签的方式(声明式导航):router-link router-link 有一个to属性用来表述去哪里 注意: router-link这个声明式导航最终会在浏览器被编译成a标签 但是千万要注意 我们不能直接使用a标签 注意: 就是我们在写路由规则的时候path路径不要写/ 要不在路由导航中就会出现问题 注意: router-link-active 每当我选中之后 会发现在路由导航中会自动添加一个类名这个类名是干什么的? 是设置当前选中的样式的 我们可以根据vue动态添加的类名 进行当前路由选中样式的设置 2.js的方式(编程式导航) 编程式导航就是使用js的方式进行跳转 方式1:最常用页面跳转 this.$router.push("/去哪里“) 方式2:替换当前页面(退不回去了) this.$router.replace("/那个页面") 方式3:this.$router.go(n)这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。 就是使用*号在path中可以匹配所有路径 通常是完成404页面的创建 重定向也是通过 routes 中的redirect属性配置来完成 同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。 hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。 history模式url里面没有#号 在开发app的时候有分享页面,这个分享出去的页面就是用vue做的,把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式 上线之后:做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上。 路由模式的切换: 在index.js中找到vueRouter实例 在其中设置mode属性 二级以及以上的路由语法相同 都是使用children属性在路由规则中进行配置 创建: 要配置二级路由的规则首先你要知道他是谁的子路由(就在谁的路由规则中写children哦配置规则) 3设置二级路由的出口 默认情况下一级路由的出口被脚手架自动添加了 但是二级路由的出口必须手动添加 使用router-view 写在一级路由中 (1)在需要接受数据的路由规则中设置 接受参数 :xxx (2)开始传递 声明式方式传递 编程式方法传递 课下自行尝试 并且添加笔记 (3)接受参数 this.$route.params.xxx query方式不需要在路由规则中配置参数 query方式不需要在路由规则中配置参数 query方式不需要在路由规则中配置参数 query方式不需要在路由规则中配置参数 query方式不需要在路由规则中配置参数 (1)发送数据 编程式方式 声明式方式课下自行尝试与加笔记 (2)接收数据 this.$route.query.xxx 1.用法上的:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.name和this.route.params.name。 2.url展示上 query 在url展示上 是key=val params在url展示上是只有val 因为query方式显示可key所以在数据传递上不那么安全 panams相对来说安全些 就是vue路由在跳转的时候自动触发的一些钩子函数 对所有的路由在切换的时候都生效 进入路由之前触发 当一个导航触发时,全局前置守卫(在进入组件之前)按照创建顺序调用。 进入路由之后触发 当一个导航触发时,全局后置钩子(在进入组件之后)调用。 只对当前这一个生效 与全局前置守卫相比路由独享守卫只是对当前路由进行单一控制参数和全局前置守卫相同 组件内守卫是对某一个自定的组件范围在切换路由的时候触发的 beforeRouteEnter(to, from, next) {}来进行进入组建前的钩子 在组件中使用beforeRouteLeave(to, from, next) {}来进行离开组件的钩子 因为vue-router是单页面应用(就是只有一个显示页面 剩下的内容都是根据url在切换 在哪一个显示页面中切换路由页面组件) 默认情况 vue在第一次加载的时候会把我们写的所有路由页面全部都加载出来 本来是没有什么太大问题的 但是一旦页面变多 (由于第一次加载的时候需要加载很多页面 所以可能会造成浏览器白屏问题/首屏加载过慢的问题) 解决:使用路由懒加载 必须掌握的方式 import 方式 了解的方式—异步组件方式 去公司之后 每个项目的启动方式可能都不相同 所以 我们需要会查看项目是使用什么命令启动的 在项目的根路径下根路径下根路径下根路径下 查看package.json文件 找到scripts 节点即可知道怎么启动的 1.下载axios npm install --save axios 2.要使用先引用 import axios from “axios” 请求拦截器 响应拦截器 1.新建一个util文件夹(就是存放一些工具库的文件夹)在新建一个api文件夹 2.创建拦截器文件并且写入拦截器内容 3.封装数据请求 4页面使用 mockjs用来在vue中创建模拟数据接口的 方便我们在后台没有给我们接口的时候让我们的项目变成动态请求 1.下载 :npm install --save mockjs 2.我们在项目中要有模拟数据 那么需要写在那个位置呢?-----创建mock文件夹来容纳模拟数据 3.在mock文件夹下创建data文件夹用来容纳模拟数据 并且创建.js文件来编写mockjs代码 4.mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 mock还需要在配置文件中引用千万不要忘 在main.js中引用 rest api 是前后端分离最佳实践,是开发的一套标准或者说是一套规范,不是框架。 规范:我告诉你应该怎么做 但是你不按照我说的可能不会出问题 但是出问题了你别找我 规则:我告诉你应该怎么做 你就必须怎么做 不按照我说的就完蛋了 restapi 就是在定义接口的时候 给接口设置更加语义化的名称 GET 获取数据 POST 发送数据 DELETE 删除 更新/修改 PUT 更多的意思是全部修改或者修改一些 PATCH 更多的意思是修改一个 发送参数的时候 其实百分之70的情况可以使用如下写法 http://localhost:3000/ceshi/get 请求参数是 name 使用params来进行参数的传递 http://localhost:3000/ceshi/delete 参数 delid 同get 修改发送方式即可 http://localhost:3000/ceshi/put 参数 putid 同get 修改发送方式即可 http://localhost:3000/ceshi/post 参数 postid post发送数据的时候使用data发送 jsonp 正向代理 必须在vue的根路径下创建一个vue.config.js文件 在其中写入如下配置 修改请求地址为/api/xxxx 注意配置的代理之后项目必须重启 cors 1.拦截器更多配置—相应拦截 失败响应的status(状态码)需要在response中获得 error.response.status 先要在项目的根路径下创建vue.config.js 自动开启 浏览器 让多个组件使用同一个挂载点,并动态切换,这就是动态组件。 在上一个demo中我们不停的切换两个标签页的内容时候,会发现在练习我们中选择好的内容,切换路由之后会恢复初始化。 keepalive就是解决状态丢失的 如果要使用 就在想保存组件状态的出口位置 使用keep-alice包裹 解决这个问题,我们可以用一个 元素将其路由出口包裹起来。在切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性 比如刚才我们动态组件举例 有三个组件 我使用包裹了动态组件 那么他就会保存所有的三个组件的状态 如果我在三个动态组件中指向保存两个的状态一个不保存怎么办? 如果两个属性都写了 那么 exclude优先级大于include 这两个生命周期函数一定是要在使用了keep-alive组件之上。 activated 类型:func 触发时机:keep-alive组件激活时使用; deactivated 类型:func 触发时机:keep-alive组件停用时调用; 除了内置指令外, 用户自定义的指令 bind:绑定指令到元素上,只执行一次 inserted:绑定了指令的元素插入到页面中展示时调用,基本上都是操作这个钩子函数 update:所有组件节点更新时调用 componentUpdated:指令所在组件的节点及其子节点全部更新完成后调用 unbind:解除指令和元素的绑定,只执行一次 思考vue中能用js的documet.getElementByxxxx进行dom操作吗? 可以使用 思考2思考vue中能用jquery进行dom操作吗? 可以使用 1.下载 npm install --save jquery\ 2.,引用 import $ from “jquery” 3,.使用 虽然在vue中 不建议不建议议不建议议不建议议不建议议不建议议不建议 大家使用dom操作 在有些极端情况下 不得不用 所以在vue中我们就是用ref进行vue中的dom操作 ref 就是在vue中给dom元素起个名字 r e f s 这 个 就 相 当 于 d o m 查 找 t h i s . refs 这个就相当于dom查找 this. refs这个就相当于dom查找this.refs.你给dom上起的ref名字 可以进行页面的dom操作 绑定到组件之上就可以获取到组件的所有属性和方法 请您能给我说下vue中父组件如何触发子组件的方法? 主要用于组件传值 正向传值 props 逆向传值 $emit() 同胞传值 (稍后讲) 夸层级/夸组件传值 ---- vuex [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-suy35PGQ-1624408588812)(.\img\3.bmp)] 新闻组件使用 联系组件的数据 传统方式进过几个正传和逆传 后期可维护性为0 简便的方式进行类似于跨层级传值 vuex 状态(数据)管理工具 vuex就是一个数据仓库 把所有的组件数据 统一的放在vuex中 那么这样一来 那个组件想使用数据 那么这个组件直接就去vuex中进行读取即可 大大简化了传递数据的复杂性 vuex集中的数据存储,方便程序中的所有组件进行访问 自动创建方式 创建vue脚手架的时候选中vuex即可 手动创建(记住) 1.下载vuex npm install --save vuex 2.创建文件夹与文件 3.开始创建store(变量存储的就是vuex实例) 4 把vuex实例引用注入到vue实例中 state的作用没有什么复杂的 就是用来创建数据的 vuex的所有数据必须必须必须只能放在state中 创建 使用数据state 在想使用数据的组件内 this.$store.state.xxx 使用vuex的state数据 state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新 vuex的数据是响应式的 那么既然想是响应式 我们如何进行修改呢? mutations 修改vuex的state数据 他只有一个作用就是修改 mutations是一个属性 他里面方的就是修改state的一个一个的方法。 创建 上面创建了一个修改的mutations 虽然有一个xiaoming的修改方法 但是我在组件页面中如何去调用它呢? 调用mutatioins中的修改方法 commit(“调用的方法名”) vuex mutations 提交载荷 payload actions 在vuex中的唯一作用就是用来处理异步操作的 创建 调用 actions 如果actions想被调用 必须必须必须要使用this.$store.dispatch(“actions名字”) 1.既然要进行异步请求 就要走vue中使用axios的那些东西 新建util 新建api 来进行请求与拦截器的封装 2.异步操作是在vuex actions中 所以我们需要在actions中创建一个方法 在方法中调用异步请求 3.在需要发送请求的组件页面中 触发actions (this.$stroe.dispatch())触发了之后这个请求就发送了 4.数据已经在actions打印出来了 由于vuex的数据需要存储在state中 所以我们需要让actions请求来得数据修改state中的某个变量 在actions中要调用commit触发mutations修改state 在页面使用 数据请求闭环示意图 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tvyxcki2-1624408588814)(.\img\4.png)] acions也可以通过dispatch向actions中传递参数 那么这个参数就是payload getters 就是vuex的计算属性 作用域 vue的计算属性处理出来的数据只能在当前组件内使用 但是vuex使用getters处理的数据可以在任何组件中多次使用 一条数据在一个组件内展示不同的形态的时候 使用vue的计算属性 一条数据在多个组件内想重复使用处理出来的不同形态数据的时候 使用vuex的getters getters是一个vuex的属性 创建: 使用 与使用state相同在组件中的计算属性当中使用 this.$store.getters.xxx来进行调用 在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。 1.在store文件夹中新建文件夹存放模块 2.编写属于组件的模块 3.在vuex的配置中引用使用 4注意 如果使用了模块在读取数据的时候就有区别了 this.$store.state.模块名.xxxx https://vant-contrib.gitee.io/vant/#/zh-CN/ 中央事件总线 eventBus 创建一个新的Vue实例,以后它就承担起了组件之间通信的桥梁了,也就是中央事件总线。 1.新建一个文件夹用来容纳中央事件总线这个vue实例 2 兄弟传值 demoa需要把数据给demob (1)现在demoa中使用$emit()把数据通过自定义事件绑定到那个vue实例上\ (2)在demob中使用$on来监听接收实例上的自定义事件 1、创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁 mixins是vue中组件的一种复用技术 它可以把组件中很多相同的属性与方法等属性 提取出来方便多个组件进行复用 1.创建一个文件夹用来容纳混入内容 2.在想使用的地方引用调用使用 在任何组件中都可以使用 在组件中即可随意使用混入中的数据 1.router下的index这个文件随着项目体量逐渐增大 会导致后期维护困难 下载 详见官网 https://element.faas.ele.me/#/zh-CN/component/quickstart 引用
// 1.引用组件
// import 是给引用进来的内容起个名字 首字母大写 from "你引用的路径"
import Home from "./components/home.vue"
export default {
name: 'App',
components: {
}
}
// 1.引用组件
// import 是给引用进来的内容起个名字 首字母大写 from "你引用的路径"
import Home from "./components/home.vue"
export default {
name: 'App',
components: {
// 2.调用
// 组件名:你引用的组件
Home
}
}
组件中的属性使用
<template>
<div>
{{text}}
</div>
</template>
<script>
export default {
data(){
return {
text:"你好么么哒"
}
}
}
</script>
<style>
</style>
组件的样式设置
<style scoped>
/* scoped当前样式仅对当前组件生效 */
div{
color:red;
}
style>
父子组件
父子组件的作用域
父子组件传值
正向传值
export default {
props:["xiaoming"],//设置接收参数
data(){
return {
zitext:"我是子组件的数据"
}
}
}
<template>
<div>
<!-- 使用props的小明数据 -->
zizizizizizzizizizi----{{xiaoming}}
</div>
</template>
<script>
export default {
props:["xiaoming"],//设置接收参数
data(){
return {
zitext:"我是子组件的数据"
}
}
}
</script>
<style>
</style>
<!-- 传递数据给子组件 -->
<Zi :xiaoming="futext"/>
props验证
生产版本也就是压缩版的文件删除了警告,所以使用非压缩版的js文件就可以看到错误逆向传值
<template>
<div>
<button @click="fun()">点我进行逆向传值button>
div>
template>
<script>
export default {
data(){
return {
num:"我是子组件的数据么么哒!!"
}
},
methods:{
fun(){
// 千万不要把$emit记成逆向传值了 他是自定以事件
// this.$emit("自定义事件的名字","你传递的数据")
this.$emit("xiaoming",this.num)
}
}
}
script>
<template>
<div>
<h1>逆向传值h1>
<Bzi @xiaoming="fun"/>
div>
template>
<script>
import Bzi from "./bzi.vue"
export default {
methods:{
// val就是子组件传递的数据
fun(val){
console.log(val)
}
},
components:{
Bzi
}
}
script>
路径别名
module.exports={
configureWebpack:{
resolve:{
alias:{
// "别名":"对应的文件夹"
"com":"@/components"
}
}
}
}
slot
slot使用
测试slot
具名槽口
路由
可以根据url的不同来切换不同的组件页面以达到用户观感上的页面切换
页面不会刷新路由创建
脚手架自动创建
与之前默认的脚手架项目区别
创建新页面过程
import Vue from 'vue'
import VueRouter from 'vue-router'
//1.引用 你要用的所有路由页面必须先引用
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import Shop from '../views/shop.vue'
Vue.use(VueRouter)
//2配置路由规则
const routes = [
{
path: '/', //url匹配的路径
name: 'Home', //当前这个规则的命名空间(给当前这个路由起个名字)
component: Home //当匹配到的时候我要显示的组件页面是什么
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/shop',
name: 'Shop',
component: Shop
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
手工创建
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
路由导航
原生html+css+js如何进行页面切换?
路由导航分类
路径通配符
重定向路由
路由规则的优先级
路由模式
const router = new VueRouter({
mode: 'history',//设置路由模式的
base: process.env.BASE_URL,
routes
})
嵌套路由/多级路由/二级三级。。。。路由
1.创建多级路由页面组件
2.配置二级路由的路由规则
坑1 不加/
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/home.vue'
import Phone from '../views/phone.vue'
import Shop from '../views/shop.vue'
import User from '../views/user.vue'
// 二级路由
import Era from '../views/er/era.vue'
import Erc from '../views/er/erc.vue'
import Erd from '../views/er/erd.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/phone',
name: 'Phone',
component: Phone
},
{
path: '/shop',
name: 'Shop',
component: Shop
},
{
path: '/user',
name: 'User',
component: User,
// 配置二级路由
// 坑1:在写二级路由的path时候先不加/
// 坑1:在写二级路由的path时候先不加/
// 坑1:在写二级路由的path时候先不加/
// 坑1:在写二级路由的path时候先不加/
children:[
{
path: 'era',
name: 'Era',
component: Era
},
{
path: 'erc',
name: 'Erc',
component: Erc
},
{
path: 'erd',
name: 'Erd',
component: Erd
},
]
},
{
path:"/",
redirect:"/home"
}
]
const router = new VueRouter({
mode: 'history',//设置路由模式的
base: process.env.BASE_URL,
routes
})
export default router
坑2 加/
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/home.vue'
import Phone from '../views/phone.vue'
import Shop from '../views/shop.vue'
import User from '../views/user.vue'
// 二级路由
import Era from '../views/er/era.vue'
import Erc from '../views/er/erc.vue'
import Erd from '../views/er/erd.vue'
Vue.use(VueRouter)
// const routes = [
// {
// path: '/home',
// name: 'Home',
// component: Home
// },
// {
// path: '/phone',
// name: 'Phone',
// component: Phone
// },
// {
// path: '/shop',
// name: 'Shop',
// component: Shop
// },
// {
// path: '/user',
// name: 'User',
// component: User,
// // 配置二级路由
// // 坑1:在写二级路由的path时候先不加/
// // 坑1:在写二级路由的path时候先不加/
// // 坑1:在写二级路由的path时候先不加/
// // 坑1:在写二级路由的path时候先不加/
// children:[
// {
// path: 'era',
// name: 'Era',
// component: Era
// },
// {
// path: 'erc',
// name: 'Erc',
// component: Erc
// },
// {
// path: 'erd',
// name: 'Erd',
// component: Erd
// },
// ]
// },
// {
// path:"/",
// redirect:"/home"
// }
// ]
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/phone',
name: 'Phone',
component: Phone
},
{
path: '/shop',
name: 'Shop',
component: Shop
},
{
path: '/user',
name: 'User',
component: User,
// 配置二级路由
// 坑2:在写二级路由的path时候加/
// 坑2:在写二级路由的path时候加/
// 坑2:在写二级路由的path时候加/
// 坑2:在写二级路由的path时候加/
children:[
{
path: '/era',
name: 'Era',
component: Era
},
{
path: '/erc',
name: 'Erc',
component: Erc
},
{
path: '/erd',
name: 'Erd',
component: Erd
},
]
},
{
path:"/",
redirect:"/home"
}
]
const router = new VueRouter({
mode: 'history',//设置路由模式的
base: process.env.BASE_URL,
routes
})
export default router
4.路由导航
坑1如果刚才创建path的时候没有加/
<router-link to="/user/era">erarouter-link>
<router-link to="/user/erc">ercrouter-link>
<router-link to="/user/erd">erdrouter-link>
坑2如果刚才创建path的时候加了/
<router-link to="/era">erarouter-link>
<router-link to="/erc">ercrouter-link>
<router-link to="/erd">erdrouter-link>
动态路由匹配 路由传参
分类
params方式
{
path: '/shopall/:随便写', //设置接受参数
name: 'Shopall',
component: Shopall
},
<router-link :to="{name:'Shopall',params:{xiaoming:'我是传递过去的参数params'}}">params声明式传参router-link>
{{this.$route.params.xiaoming}}
query方式
query与params区别
路由守卫/路由卫士/路由钩子/路由验证
全局守卫
全局前置守卫
vue-router 提供的 router.beforeEach((to,from,next)=>{})可以方便地实现全局前置导航守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由
next: 下一步执行// 全局守卫
// to:去哪里
// from:从哪来
// next:下一步
router.beforeEach((to,from,next)=>{
console.log(to)
console.log(from)
if(to.path=="/login"||to.path=="/zhuce"){
next()
}else{
alert("您没有登录请登录后在试一试")
next(false)
}
})
全局后置守卫
vue-router 提供的 router.afterEach((to, from) => {})实现全局后置守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由路由独享的守卫
在路由配置上直接定义 beforeEnter 进行路由独享守卫定义 {
path: '/',
name: 'Home',
component: Home,
// 路由独享
beforeEnter(to,from,next){
alert("当前为vip页面 请您登录后访问")
next("/login")
}
},
组件内守卫
进入之前
离开的时候
路由懒加载
使用
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
// 懒加载的方式
{
path: '/home',
name: 'home',
component: () => import('../views/home.vue')
},
{
path: '/phone',
name: 'phone',
component: () => import('../views/phone.vue')
},
{
path: '/shop',
name: 'shop',
component: () => import('../views/shop.vue')
},
{
path: '/user',
name: 'user',
component: () => import('../views/user.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
{
path: '/shop',
name: 'shop',
component: resolve=>(require(["引用的组件路径"],resolve))
},
扩展小知识----脚手架项目怎么启动?
axios与拦截器封装
基本写法(不建议使用 太low 公司也不用 但是不讲不行)
拦截器
请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易。
响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。创建
import axios from "axios"
// 创建axios 赋值给常量service
const service = axios.create();
// 添加请求拦截器(Interceptors)
service.interceptors.request.use(function (config) {
// 发送请求之前做写什么
return config;
}, function (error) {
// 请求错误的时候做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
// 封装数据请求
// 引用拦截器
import service from "@/util/request.js"
// 2.开始封装请求
export function getlink(url){
return new Promise((resolve,reject)=>{
service.request({
// 原来的axios怎么写 现在就怎么写
url,
method:"GET"
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
模拟数据mockjs
import Mock from "mockjs"
// 创建第一个请求
注意大小写 get要小写
// Mock.mock("请求地址你自己写","请求方式get/post",require("你的模拟数据json的地址"))
Mock.mock("/xiaoming/xiaohong","get",require("./data/demo.json"))
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
require("./mock")//引用mock
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
后台发送参数
怎么给后台发送参数
GET
import service from "@/util/service.js"
export function getlink(url,params){
return new Promise((resolve,reject)=>{
service.request({
url,
method:"GET",
// get发送数据的时候使用params发送
params
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
DELETE
PUT
POST
import service from "@/util/service.js"
export function postlink(url,data){
return new Promise((resolve,reject)=>{
service.request({
url,
method:"POST",
// post发送数据的时候使用data发送
data
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
mounted(){
// post发送参数的时候是没有办法直接发送的 因为默认情况下没有
// 办法解析
// 所以我们要设置post参数并且解析参数
let usp=new URLSearchParams()
// usp.append("你发送的key","你发送的val")
usp.append("postid",9999)
postlink("/api/ceshi/post",usp).then((ok)=>{
console.log(ok)
})
}
解决跨域
module.exports={
// 配置跨域
devServer: {
proxy: { //配置跨域
'/api': {
target: 'http://localhost:3000/', //这里后台的地址模拟的;应该填写你们真实的后台接口
changOrigin: true, //允许跨域
pathRewrite: {
'^/api': ''
}
},
}
},
}
拦截器更多配置与token的前端使用
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么-----后台能后正常给我们相应数据拦截的地方
return response;
}, function (error) {
// 对响应错误做点什么-----404 500 403出现的位置
console.log(error.response.status)
switch (error.response.status) {
case 500:
// 处理的操作
alert("当前连接超时")
break;
case 404:
// 处理操作
alert("您访问的页面不存在")
// 把页面跳转到首页
break;
default:
return Promise.reject(error);
}
return Promise.reject(error);
});
扩展知识----自动开启浏览器与端口修改
module.exports={
devServer:{
port:8899// 修改端口
}
}
module.exports={
devServer:{
port:8899,// 修改端口
open:true//自动开启浏览器
}
}
动态组件
动态组件
keep-alive—解决状态丢失
也就是说之前的状态丢失。原因是每次切换路由的时候,Vue 都创建了一个新的 组件实例使用
使用在动态组件之上
动态组件的属性
include 需要缓存谁
exclude 不想缓存谁
注意
keep-alive 的钩子函数
自定义指令
局部指令定义:
directives:{
自定义指令的名字:{
自定义指令钩子函数(el){
操作逻辑
}
}
},自定义指令钩子函数
自定义指令
我是测试自定义指定的元素
ref
mounted(){
console.log(document.getElementsByTagName("p")[0].innerHTML)
}
为什么用ref
使用
<em ref="demoem">我是测试vue的ref的例子em>
funb(){
this.$refs.demoem.style.color="pink";
}
ref绑定的位置
ref 绑定到dom元素之上
ref绑定到子组件之上
vuex
传统跨层级传值
VUEX基本
创建vuex
import Vue from 'vue'//引用vue
import Vuex from 'vuex' //引用vuex
Vue.use(Vuex)// 在vue中use(使用)vuex
// 暴露 vuex实例
export default new Vuex.Store({
})
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'//引用vuex实例
Vue.config.productionTip = false
new Vue({
router,
store,//把vuex注入到vue实例中进行使用
render: h => h(App)
}).$mount('#app')
vuex 的5大核心API
state—数据源
import Vue from 'vue'//引用vue
import Vuex from 'vuex' //引用vuex
Vue.use(Vuex)// 在vue中use(使用)vuex
// 暴露 vuex实例
export default new Vuex.Store({
state:{//存放数据的 可以存放任何数据
text:"我是一个字符串",
num:123,
arr:[1111,2222,3333,444,5555]
}
})
<template>
<div class="about">
<h1>This is an about pageh1>
<h1>{{this.$store.state.text}}h1>
div>
template>
mutations
import Vue from 'vue'//引用vue
import Vuex from 'vuex' //引用vuex
Vue.use(Vuex)// 在vue中use(使用)vuex
// 暴露 vuex实例
export default new Vuex.Store({
state:{//存放数据的 可以存放任何数据
text:"我是一个字符串",
num:123,
arr:[1111,2222,3333,444,5555]
} ,
mutations:{//修改state的数据
// 修改方法1(state 这个形参就是上面的state){},
// 修改方法2(state 这个形参就是上面的state){},
// 修改方法3(state 这个形参就是上面的state){},
// 修改方法4(state 这个形参就是上面的state){},
// 修改方法5(state 这个形参就是上面的state){},
xiaoming(state){
state.text="呵呵"
}
}
})
This is an about page
{{this.$store.state.text}}
xiaoming(state,payload){
state.text=payload.name
}
在组件调用
this.$store.commit("xiaoming",{key:val,key:val})
扩展------必须要知道 很重要 vuex数据刷新丢失
<template>
<div class="about">
<h1>This is an about page</h1>
<h1>{{this.$store.state.text}}</h1>
<button @click="fun()">点我修改</button>
</div>
</template>
<script>
export default {
// 解决vuex数据刷新丢失的问题
created () {
//在页面加载时读取localStorage里的状态信息
if (localStorage.getItem("data") ) {
//replaceState替换数据 Object.assign合并对象
this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(localStorage.getItem("data"))))
}
//在页面刷新时将vuex里的信息保存到localStorage里
window.addEventListener("beforeunload",()=>{
localStorage.setItem("data",JSON.stringify(this.$store.state))
})
},
// 解决vuex数据刷新丢失的问题
methods:{
fun(){
// 调用修改调用修改使用this.$store.commit("mutations的方法名")
this.$store.commit("xiaoming")
}
}
}
</script>
actions 处理异步操作
actions 是vuex的一个属性 里面写的是一个一个的方法方法中存的就是异步操作import Vue from 'vue'//引用vue
import Vuex from 'vuex' //引用vuex
Vue.use(Vuex)// 在vue中use(使用)vuex
// 暴露 vuex实例
export default new Vuex.Store({
state:{//存放数据的 可以存放任何数据
text:"我是一个字符串",
num:123,
arr:[1111,2222,3333,444,5555]
} ,
mutations:{//修改state的数据
// 修改方法1(state 这个形参就是上面的state){},
// 修改方法2(state 这个形参就是上面的state){},
// 修改方法3(state 这个形参就是上面的state){},
// 修改方法4(state 这个形参就是上面的state){},
// 修改方法5(state 这个形参就是上面的state){},
xiaoming(state,payload){
state.text=payload.name
}
},
actions:{//处理异步操作
// 一个一个的方法
demoa(){console.log("我是第一个异步")},
demob(){console.log("我是第2个异步")},
democ(){console.log("我是第3个异步")},
}
})
{{this.$store.state.text}}
actions进行vue异步请求数据闭环
import Vue from 'vue'
import Vuex from 'vuex'
// 引用
import {getlink} from "@/api/getapi.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
// 需要在vuex中发送异步操作
actiondemoa(){
getlink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187").then((ok)=>{
console.log(ok)
})
}
}
},
modules: {
}
})
{{ msg }}
import Vue from 'vue'
import Vuex from 'vuex'
// 引用
import {getlink} from "@/api/getapi.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {
arr:[]
},
mutations: {
dataarr(state,payload){
state.arr=payload
}
},
actions: {
// 需要在vuex中发送异步操作
actiondemoa(context){
getlink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187").then((ok)=>{
console.log(ok.data.data.commentList)
// 把请求来得数据交给mutations修改
context.commit("dataarr",ok.data.data.commentList)
})
}
},
modules: {
}
})
payload
getters
vuex的getters与传统vue的computed计算属性有什么区别?
getters:{//vuex的计算属性
newtext(state){
return state.text.toUpperCase()
}
},
modules
module:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。export let aboutm={
state: {
demoa:"111",
demob:"22",
democ:"113331",
},
mutations: {
},
actions: {
},
}
import Vue from 'vue'
import Vuex from 'vuex'
import {aboutm} from "./modules/aboutm.js"
import {homem} from "./modules/homem.js"
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
aboutm,homem
}
})
vantui
组件传值
正向传值 props
逆向传值 $emit() ref
同胞兄弟传值 eventBus
// 中央事件总线就是新建一个vue实例用来当兄弟组件的数据桥梁
import Vue from "vue"
export default new Vue()
2、在需要传值的组件中用bus. e m i t 触 发 一 个 自 定 义 事 件 , 并 传 递 参 数 ( e m i t 前 加 美 元 符 ) 3 、 在 需 要 接 收 数 据 的 组 件 中 用 b u s . emit触发一个自定义事件,并传递参数(emit前加美元符) 3、在需要接收数据的组件中用bus. emit触发一个自定义事件,并传递参数(emit前加美元符)3、在需要接收数据的组件中用bus.on监听自定义事件,并在回调函数中处理传递过来的参数跨组件传值 vuex
Mixins 混入
局部混入
let mixinsdemo={
methods:{
funb(){
console.log("我是一个方法")
}
},
data(){
return {
textm:"我是混入的变量"
}
}
}
export default mixinsdemo
全局混入
在main中引用 并且使用
import MinXin from ‘@/components/MinXins/index.js’
Vue.mixin(MinXin);路由拆分—与大纲内容无关(了解掌握)
elementui
main.js中添加
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);