在众多的语言排名中,JavaScript 已经非常靠前,它是前端的核心编程语言,我们可以利用 js 开发 动态 效果的网页,也可以开发 app,为了简化 JavaScript 的使用,在其基础上,发展出两个门派:
真实 DOM 操作的 jQuery 门派,例如:bootstrap、layui、easyui 都使用了 jQuery 技术。
虚拟 DOM 操作门派,复杂的如 angular.js ,简单的国产框架
我们以虚拟 DOM 操作的 vue.js 为例它有以下优点:
官方解读:Vue (读音 /vju:/,类似于 view) 是一套用于构建用户界面的"渐进式框架"。与其它大型框架 不同的是,Vue 被设计为可以"自底向上逐层应用"。Vue 的核心库只关注"视图层",易于上手,便于与第三方库 或既有项目整合。
简单来说,Vue 就是一个用于搭建表单项繁多且内容需要根据用户的操作进行修改的网页应用的框架。
使用 JQuery 也可以完成相应的功能啊,为什么还要使用 Vue?
jQuery 是使用选择器($)选取 DOM 对象,对其进行赋值、取值、事件绑定等操作,其实和原生的 HTML 的 区别只在于可以更方便的选取和操作 DOM 对象,而数据和界面是在一起的。比如需要获取 label 标签的内容: $(“lable”).val();,它还是依赖 DOM 元素的值。
Vue 则是通过 Vue 对象将数据和 View 完全分离开来了。对数据进行操作不再需要引用相应的 DOM 对象,可 以说数据和 View 是分离的,他们通过 Vue 对象这个 vm 实现相互的绑定。这就是传说中的 MVVM。
让我们投向 Vue.js 的主要原因在于:它能让团队书写用 js 更容易并且简化了 js。上手 Vue.js 是相当容易 的。它的源码有着很高的可读性,如果你需要仅用他的文档便可入门。你不必使用任何额外的库。如果需要可以 和 jQuery 协同工作。他有许多的插件,但并非必须。
在 html 中,使用 script 标签引入 vue.js 文件:
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
在 html 标签内添加一个 dom 元素作为 Vue
<body>
<div id="app" class="app">div>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
body>
创建 Vue 对象的实例:
<body>
<div id="app">
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {}
})
script>
body>
我们已经成功创建了第一个 Vue 应用!现在数据 data 和 DOM(id=“app”的 div)已经被建立了关联,所有 东西都是响应式的。(所谓响应式即是 vue 实现的双向数据绑定,接下来会详细介绍)
任务一: 使用双大括号将数据编译成普通文本,并输出到插值的位置。
<div id="app">
{{msg}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue"
}
})
script>
结果:
插值标签将会被替代为对应数据对象上 msg 属性的值。无论何时,绑定的数据对象上 msg 属性发生了改变, 插值处的内容都会更新。
Vue 的数据绑定是数据驱动。即:当数据发生变化时会触发 html 页面更新,所有相关联绑定的值也会随之 一起变化。
任务二: vue 的数据绑定不仅限于简单的属性键值,VUE 对所有的绑定,都支持 JavaScript 表达式绑定, 如下例:
<div id="app">
{{count > 0?'是的':'不是'}}<br />
{{count+1}}<br />
{{msg.toUpperCase()}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue",
count:0
}
})
script>
这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。
指令 (Directives) 是带有v-
前缀的特殊特性,绑定在 DOM 标签上。指令的职责是,当表达式的值改变 时,将其产生的连带影响,响应式地作用于 DOM。
v-text 的效果完全等价于使用双大括号绑定的效果。例如:
<div id="app">
<span v-text="msg">span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue"
}
})
script>
结果:
使用 v-text 指令绑定数据
此时的效果完全等价于使用双大括号绑定的效果,那么二者有没有什么区别呢?
答案是有。区别:v-text 是指令,只能绑定在 DOM 标签上,{{}}绑定 可以放置在 vue 挂在目标节点内的任 意位置,而不需要额外的 DOM 标签。
v-show 指令将根据表达式 isShow 的值的真假来显示/隐藏元素。
v-show 所绑定的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
任务四: 使用 v-show 指令实现指定内容的显示与否。
<div id="app">
<span v-show="isShow">我是span标签,能看到我不span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
//当这个变量为true时,span标签显示,当为false时,隐藏
isShow:true
}
})
script>
vue 条件指令包括 v-if,v-else,v-else-if 用法与 js中的条件语句相同
任务五: 使用 v-if/v-else 指令实现字符的大小写切换功能。
<div id="app">
<span v-if="lowerCase" v-text="msg">span>
<span v-else v-text="msg.toUpperCase()">span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue",
lowerCase:false
}
})
script>
v-else 使用限制: 上一个兄弟节点必须包含 v-if 或 v-else-if 指令之一
v-else-if 相当于 js 中的 if-else-if 语句:
任务六: 使用 v-else-if 指令实现性别选择实时显示选择结果的功能。
<div id="app">
<label>
<input type="radio" v-model="sex" value="0" />男
label>
<label>
<input type="radio" v-model="sex" value="1" />女
label>
<label>
<input type="radio" v-model="sex" value="-1" />保密
label>
性别:
<span v-if="sex==0">男span>
<span v-else-if="sex==1">女span>
<span v-else>保密span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
sex:-1
}
})
script>
v-for 循环数组或对象,表达式是 obj in objs 形式的特殊语法。objs 是一个数组或对象,obj 是元素迭代 的别名。
也可以使用 (obj,index) in objs 形式的表达式。
语法:
<ul>
<li v-for="n in arr">
{{n}}
li>
ul>
<ul>
<li v-for="(n,i) in arr">
index:{{i}} / value:{{n}}
li>
ul>
案例:
任务七: 使用 v-for 指令分别实现循环数组和对象的功能。
<div id="app">
<h4>遍历lessons数组h4>
<ul>
<li v-for="l in lessons">
{{l}}
li>
ul>
<h4>带下标的遍历数组h4>
<ul>
<li v-for="(l,i) in lessons">{{i}}:{{l}}li>
ul>
<h4>遍历对象h4>
<ul>
<li v-for="s in student">{{s}}li>
ul>
<h4>带属性名遍历对象h4>
<ul>
<li v-for="(s,i) in student">{{i}}:{{s}}li>
ul>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
//student对象
student:{
id:1,
name:"张三",
age:20,
sex:"男"
},
//lessons数组
lessons:["h5","css","js","vue"]
}
})
script>
基础指令及双大括号绑定只能解决单向数据绑定的问题,即当 data 中的数据发生改变时,页面的数据会随 之变化,而 v-model 指令(它负责监听用户的输入事件以更新数据)在表单 及 元素上创建 双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
任务八: 使用 v-model 指令实现如下的数据双向绑定功能,即实时显示选择结果。
<div id="app">
<input type="checkbox" v-model="isShow" />显示/隐藏
<br />
<span v-show="isShow">能看到我span标签不span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
isShow:true
}
})
script>
当单选框被选中时上面一行字体显示,再次点击时候单选框处于不被选中的状态此时上面一行字体不显示, 不需要刷新就能实现数据的实时传送,状态实时改变,这就是数据的双向绑定。
修饰符(Modifiers)是以半角句号 . 指明的特殊后缀,用于指出一个指定应该以特殊方式绑定。
常见的指令修饰符有.number .trim 和 .lazy
,下面对这些指令修饰符进行一一介绍。
任务九:体会.number 修饰符作用为自动将用户的输入值转为数值类型。
<div id="app">
<input v-model.number="n" />
{{n+1}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:1
}
})
script>
.number 修饰符可以将输入的值转化为 Number 类型 ,否则虽然你输入的是数字但它的类型其实是字符 串类型,在数字输入框中比较有用。
任务十: 练习.trim 修饰符:自动过滤用户输入的首尾空白字符。
<div id="app">
<input v-model.trim="n" />
{{n}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:1
}
})
script>
在输入框中,v-model 默认是同步数据,使用 .lazy 会转变为在 change 事件中同步,也就是在失去焦点 或者按下回车键时才更新。
任务十一: 使用.lazy 修饰符观察当输入数字时对应的内容会不会实时显示。
<div id="app">
<input v-model.lazy="n" />
{{n}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:1
}
})
script>
在输入框中输入一串数字,有.lazy 修饰符修饰,并不会实时的同步数据,而是输入完成后点击空白处才能 同步 。
它是一个 vue 指令,用于绑定 html 属性,v-bind 指令可以被简写为":"。
测试
<div id="app">
<img v-bind:src="imgSrc"/>
<img :src="imgSrc"/>
<img :src="'img/'+img"/>
<button :disabled="isDis">确定button>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
imgSrc:"http://via.placeholder.com/100x100",
img:"1.jpg",
isDis:true
}
})
script>
v-bind 通常用来绑定属性的,格式是 v-bind:属性名 = "值"
,简写:属性名 = "值"
。
v-bind动态更新class,分为三种方法:对象语法和数组语法,还有就是变量语法。
使用 v-bind:class,v-bind:style 绑定多个值,vue 对 class 和 style 这两个 html 属性进行了一定程度 的增强。
只有 v-bind:class 设置的属性会追加原有属性,而 v-bind 绑定的其他属性是会覆盖原有属性。
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
<style type="text/css">
.isActive{
width: 100px;
height: 100px;
border: 3px solid #096;
}
.hasError{
background-color: red;
}
style>
head>
<body>
<div id="app">
<p :class="cssObj">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 基于对象的 */
cssObj:{
/* 当isActive变量为true时,在标签的class属性里自动拼接这个类名,为false时不拼接,下面那个也一样 */
isActive:true,
hasError:true
}
}
})
script>
body>
html>
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
<style type="text/css">
.isActive{
width: 100px;
height: 100px;
border: 3px solid #096;
}
.hasError{
background-color: red;
}
style>
head>
<body>
<div id="app">
<p :class="cssArr">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 数组是没有办法单独设置类是否拼接的,但是可以进行优化 */
cssArr:["isActive","hasError"]
}
})
script>
body>
html>
使用数组的话是没有办法单独设置类是否拼接的,但是可以优化:
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
<style type="text/css">
.isActive{
width: 100px;
height: 100px;
border: 3px solid #096;
}
.hasError{
background-color: red;
}
style>
head>
<body>
<div id="app">
<p :class="['hasError',jihuo?'isActive':'']">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 数组是没有办法单独设置类是否拼接的,但是可以进行优化 */
jihuo:true
}
})
script>
body>
html>
当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
<div id="app">
<p :class="['hasError',{isActive:jihuo}]">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 数组是没有办法单独设置类是否拼接的,但是可以进行优化 */
jihuo:false
}
})
script>
class 属性的值仅在 jihuo的值为 true 时包含样式 isActive
v-bind:style
的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名
这样写是把css写到js里面,增加了代码的耦合度,不推荐使用
代码:
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
head>
<body>
<div id="app">
<p :style="styObj">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 里面不能写-,比如background-color,会报错 */
styObj:{
width:"100px",
height:"100px",
background:"red"
}
}
})
script>
body>
html>
页面渲染结果:
<p style="width:100px;height:100px;background:red;">
这是一个P标签
p>
注意:里面不能写-
,比如background-color,会报错
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.bootcss.com/vue/2.5.15/vue.js">script>
head>
<body>
<div id="app">
<p :style="styArr">这是一个P标签p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
/* 里面不能写-,比如background-color,会报错 */
styArr:[{
width:"100px"
},{
height:"100px"
},{
background:"#096"
}]
}
})
script>
body>
html>
style 绑定数组时,数组中的每个有效的 style 对象,都将被输出到 html 标签的 style 属性中。
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂 载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期的钩子函数,这给了用户在不同阶段添加自己代码的机会。
首先每个 Vue 应用都是通过 Vue 函数创建一个新的 Vue 实例开始的。
如下代码
var app = new Vue({
//选项
})
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 Dom、渲染→更新→渲 染、销毁等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。
Vue生命周期图示:
我们已经知道 Vue 实例对象从创建到销毁的过程中会发生各种事件,每种事件发生时,都可以有对应的 function 被调用,在不同的 function 中,我们访问对象的方式略有不同,下边的示例,你不需要完全掌握,但 以后开发中当你有需要时,可以参考这些示例,迅速完成代码构建。
方法的完整版:
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue!"
},
beforeCreate: function(){
console.log("--------------beforeCreate创建之前--------------");
console.log(this.$el);// undefined
console.log(this.$data);// undefined
console.log(this.msg);// undefined
}
})
ES6简写版:
beforeCreate() {
console.log("----------------beforeCreate创建之前----------------");
console.log(this.$el);//undefined
console.log(this.$data);//undefined
console.log(this.msg);//undefined
}
Vue 实例对象或组建实例被创建,Vue 对象数据观测 data 数据对象和 event 事件开始初始化但尚未初始化完成时。
<div id="app">
{{msg}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue!"
},
beforeCreate: function(){
console.log("--------------beforeCreate创建之前--------------");
console.log(this.$el);// undefined
console.log(this.$data);// undefined
console.log(this.msg);// undefined
}
})
script>
此时,Vue 实例内的对象均是 undefined 不可访问。
在实例创建完成后被立即调用。在这一步,数据观测data、event均已被创建 -
任务 2:使用 created钩子函数,输出 e l 、 el、 el、data对象,观看结果
<div id="app">
{{msg}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue!"
},
created: function(){
console.log("--------------created创建之后--------------");
console.log(this.$el);// undefined
console.log(this.$data);// object
console.log(this.msg);// hello vue!
}
})
script>
此时的 DOM 对象还未被创建完毕。
将 Vue 实例挂载到 DOM 对象之前。vm.$el 对象已创建,但未挂载到页面上。此时获取到的DOM 对象中的指 令尚未被计算。
<div id="app">
{{msg}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue!"
},
beforeMount: function(){
console.log("--------------beforeMount挂载之前--------------");
console.log(this.$el);// {{msg}}
console.log(this.$data);// object
console.log(this.msg);// hello vue!
}
})
script>
注意:此时产生的是 Virtual DOM 对象。
在原 DOM 对象被 Vue 创建的 vm.$el 替换到页面上之后。此时页面上才会存在相对于的 DOM 节点。一般理解 为 DOM 对象创建完毕。
任务 4:使用 mounted 钩子函数,输出 e l 、 el、 el、data 对象,观看结果。
<div id="app">
{{msg}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:"hello vue!"
},
mounted: function(){
console.log("--------------mounted挂载之后--------------");
console.log(this.$el);// hello vue!
console.log(this.$data);// object
console.log(this.msg);// hello vue!
}
})
script>
注意:此时的 DOM 是真实 DOM!
当数据发送变化时,组件更新之前。
调用时机:数据更新时调用,vm.$el 替换到页面上之前。
任务 5:使用 beforeUpdate 钩子函数,并在观看函数的运行时机和结果。
<div id="app">
<input type="checkbox" v-model="isCheck" />切换<br />
isCheck的值为:<span v-text="isCheck" id="span">span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
isCheck:true
},
beforeUpdate: function(){
console.log("--------------beforeUpdate修改之前--------------");
console.log(this.isCheck);
console.log("真实DOM的值为:" + document.getElementById("span").innerHTML)
}
})
script>
组件更新之后。
调用时机:新的数据更新到 DOM 节点上之后。
任务 6:使用updated 钩子函数,观察执行时机和与 beforeUpdate的不同。
<div id="app">
<input type="checkbox" v-model="isCheck" />切换<br />
isCheck的值为:<span v-text="isCheck" id="span">span>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
isCheck:true
},
updated: function(){
console.log("--------------updated修改之后--------------");
console.log(this.isCheck);
console.log("真实DOM的值为:" + document.getElementById("span").innerHTML)
}
})
script>
结果:
实例销毁之前调用。在这一步,实例仍然完全可用。
<div id="app">
<button type="button" @click="add">+1button>
<button type="button" @click="destroy">销毁button><br />
{{n}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:1
},
methods:{
add:function(){
this.n++;
},
destroy:function(){
this.$destroy();
}
},//销毁之前,通常用于善后操作,比如清除缓存等。
beforeDestroy:function(){
console.log("---------beforeDestroy销毁之前----------");
console.log("销毁之前");
}
})
script>
点击销毁按钮后,+1按钮将不能进行改值操作。
Vue 实例销毁后调用
调用后 Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
任务 8:使用 destroyed 钩子函数,观察与 beforeDestroy 函数运行时机的区别。
<div id="app">
<button type="button" @click="add">+1button>
<button type="button" @click="destroy">销毁button><br />
{{n}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:1
},
methods:{
add:function(){
this.n++;
},
destroy:function(){
this.$destroy();
}
},//销毁之后,基本不用
destroyed:function(){
console.log("---------destroyed销毁之后----------");
console.log("销毁之后");
}
})
script>
在 jQuery 中,直接提供了 ajax 函数(例如:$.post),可以和服务器端进行数据交互,但 vue.js 本身不包 含 ajax 相关函数,我们从 jQuery 中,提取了 ajax。
任务 9:发送 ajax 请求到 stuapi,请求所有的角色信息,并将信息以li的形式显示到页面中。
<div id="app">
<ul>
<li v-for="m in msg">
ID:{{m.Id}},Name:{{m.Name}}
li>
ul>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:""
},
mounted:function(){
$.post("http://stuapi.ysdjypt.com/api/GetRolesAll",{
token:'eef6233e-32fb-43c1-b572-aa74b2aa7375'
},function(res){
console.log(res);
app.msg=res;
},"json");
}
})
script>
其实使用Vue
是不用ajax
的,通常都是使用axios
发送请求
axios中文说明: 使用说明 · Axios 中文说明 · 看云 (kancloud.cn) 。
methods 是一个包含了{key:function}的对象。通过实例可以直接访问这些函数,也可以在指令的表达式中 调用。
methods 将被混入到 Vue 实例中,可以直接通过 Vue 实例访问这些方法,或者在指令表达式中使用。方法中 的 this 自动绑定为 Vue 实例。
定义方法全写:
<button type="button" v-on:click="add()">button>
简写:
<button type="button" @click="add()">button>
任务 1-1:简单使用 methods,点击按钮时,改变原有标签中的值。
<div id="app">
{{n}}<br />
<button type="button" @click="add()">+1button>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:0
},
methods:{
//定义方法
add:function(){
this.n++;
}
}
})
script>
<div id="app">
<input type="text" v-model.number="n" /><br />
{{a}}<br />
<button type="button" @click="add(n)">+{{n}}button>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
a:0,
n:0
},
methods:{
//定义方法
add:function(n){
this.a = this.a + n;
}
}
})
script>
computed 在 Vue 中被称作“计算属性”。我们之前所学面向对象语言中,大家都知道类中可以有属性和方法:
对于 Vue 而言,我们可以在 data 中,定义属性,但有些属性不需要存储(比如:可以由已知属性推导出来), 这时候定义到 computed 中是最合适的,定义到 computed 中的被称为计算属性,如果计算属性是可读可写的,这 时候需要使用 getter 和 setter(C#和 Java 中都有类似的概念),如果计算属性是只读的,我们既可以使用 getter, 也可以直接通过定义方法(这样更简单);
任务 2-1:阅读下边的代码 ,学习在 Vue 中如何使用 computed 计算属性
<div id="app">
商品名:{{product.name}}<br />
单价:{{product.price}}<br />
数量:{{product.num}}<br />
<button type="button" @click="add()">+button>
<button type="button" @click="sub()">-button><br />
总价方法一:{{totalMoney}}<br />
总价方法二:{{totalMoney2}}<br />
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
product:{
name:"铅笔",
price:3,
num:2
}
},
methods:{
//执行方法,返回pronum这个属性对应的加1和减1
add:function(){
return this.pronum++;
},
sub:function(){
return this.pronum--;
}
},
computed:{
//可以省略get方法,但是这样写就不可以写set方法了,只能得到,不能获取
totalMoney:function(){
return this.product.price * this.product.num
},
// 属性有get、set方法
totalMoney2:{
get:function(){
return this.product.price * this.product.num
}
},
/*
* get方法用于获取值赋值给属性,
* 当属性发生改变的时候,执行set方法。
* newVal形参是属性发生改变后的值,进行判断是否小于0
* 如果小于0则提示不正确,进行提示 ,如果大于等于0则将新值赋值给商品数量。
*/
pronum:{
get:function(){
return this.product.num;
},
set:function(newVal){
if(newVal<0){
alert("商品数量不能小于0");
}else{
return this.product.num = newVal;
}
}
}
}
})
script>
不断点击按钮“减少数量”,当数量减少到0一下的时候,就会提示了。
小结:
watch 用来观察某个属性,当被观察的属性的值发生变化时,对应的 function 得以执行,此 function 有两 个参数,新值和老值,如果我们不干预的话,新值会被采纳,当然我们也可以重新使用老值来恢复。
watch 是一个对象{key:String | Function | Object | Array}
,键是需要观察的表达式,值是对应的回调 函数。值也可以是方法名,或者包含选项的对象。
Vue 实例将会在实例化时调用$watch()方法,遍历 watch 对象的每一个属性。
任务 3-1:简单使用 watch 来观察文本框的变化。
<div id="app">
名:<input type="text" v-model="ming"/><br />
姓名:{{quanming}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
xing:'张',
ming:'',
quanming:''
},
watch:{
//newVal:新值 oldVal:旧值
ming:function(newVal,oldVal){
console.log(newVal);
console.log(oldVal);
this.quanming = this.xing + newVal;
}
}
})
script>
任务讲解:我们在watch 中观看或者叫“监听”了ming
这个属性,当这个属性发生变化时就触发里边的函数。
事件是面向对象中 1 个非常重要的概念,它存在的原因是各种运行平台(PC 平台、手机平台)本身支持事 件(例如:所有的交互,键盘输入、鼠标点击、手指触碰等),作为运行在平台上的应用程序,只要涉及到交互, 自然都需要支持事件。
事件机制允许我们提前预制一些方法,当事件发生时,这些预制的方法就会被执行,事件和方法之间的关系 包括:
可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。v-on 等价于@+事件名,例如:v-on:click=function
等价于@click=function …
任务1:设置一个按钮,点击时让数字加1。
<div id="app">
<button type="button" @click="n++">点我button><br />
您一共点击了{{n}}次按钮
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
n:0
}
})
script>
其它事件如:blur、change、focus、submit 等标签或 form 事件都可以通过 v-on 指令绑定
使用这个可以自定义事件。
语法结构:
vm.$on(event,callback)
参数结构入下:
通过 vm. o n 监 听 当 前 实 例 上 的 自 定 义 事 件 。 事 件 可 以 由 v m . on 监听当前实例上的自定义事件。事件可以由 vm. on监听当前实例上的自定义事件。事件可以由vm.emit 触发。回调函数会接受所有传入事件触发函数的额外参数。(结合下面vm.$emit一起举例)
语法结构:
vm.$emit(event, [...args])
触发当前实例上的事件。附加参数都会传给监听器回调。
任务 2:通过 vm. o n 自 定 义 事 件 并 绑 定 执 行 方 法 , 通 过 v m . on 自定义事件并绑定执行方法,通过 vm. on自定义事件并绑定执行方法,通过vm.emit 触发自己定义的事件。
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
created: function(){
//自定义test方法,方法接收msg参数
this.$on('test',function(msg){
//控制台打印msg
console.log(msg);
})
}
})
//执行test自定义方法,参数为hi
app.$emit('test','hi');
script>
结果:
语法结构:
vm.$off(event,callback)
作用:移除自定义监听事件,作用和 vm.$on 相反。
参数解析如下:
用法3条
如果没有提供参数,则移除所有的事件监听器。
如果只提供了事件,则移除该事件所有的监听器。
如果同时提供了事件与回调,则只移除这个回调的监听器。
任务 3:编写实验代码,验证以上“用法3条”用法。
<div id="app">
<button type="button" @click="cli()">点我有惊喜button><br />
<button type="button" @click="removefA()">点击移除fAbutton><br />
<button type="button" @click="removetest()">点击删除test的所有事件绑定方法button><br />
<button type="button" @click="removeAll()">点击删除app内所有事件绑定方法button><br />
<span v-html="msg">span>
div>
<script type="text/javascript">
function fA(){
app.msg += 'fA
';
}
function fB(){
app.msg += 'fB
';
}
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
msg:''
},
methods:{
cli: function(){
this.$emit('test');
},
removefA: function(){
this.$off('test',fA);
},
removetest: function(){
this.$off('test')
},
removeAll: function(){
this.$off();
}
},
created: function(){
this.$on('test',fA);
this.$on('test',fB);
}
})
script>
完成一个购物车案例。
执行效果如下:点击后边的+和-时,数量会变,同时共计也会变。
<div id="app">
<h4>我的购物车h4>
<ul>
<li v-for="c in carts">
名称:{{c.name}},价格:{{c.price}},数量:{{c.num}}
<button type="button" @click="add(c)">+button>
<button type="button" @click="c.num>0 && subtract(c)">-button>
li>
ul>
总计:¥{{totalMoney}}
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
carts:[
{name:'香蕉',price:2,num:1},
{name:'苹果',price:1.2,num:2},
{name:'西瓜',price:8,num:3},
]
},
methods:{
add: function(c){
c.num++;
},
subtract: function(c){
c.num--;
}
},
computed:{
//计算所有商品的总价
totalMoney: function(){
var sum = 0;
for (var i = 0; i < this.carts.length; i++) {
sum += this.carts[i].price * this.carts[i].num
}
//保留小数点后两位
return sum.toFixed(2);
}
}
})
script>
触发事件时可以传入参数。事件本身的 event 对象可以使用$event 被当做参数传入。
<div id="app">
<button type="button" @click="getEle($event)">点我button>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
methods:{
getEle: function(e){
console.log(e);
//打印e的初始目标
console.log(e.currentTarget);
}
}
})
script>
条件事件是常用的一种应用场景。既:当表达式满足条件时,才会触发相应的事件。
具体示例第5.5章节里有具体举例与说明。
需要注意的是:我们平时在直接绑定函数时是不需要加“()”的,但是当 v-on 中有表达式时,就必须 带上“()”,否则 Vue 无法判断后边的内容是表达式还是方法名。
dom 元素在浏览器内存中是以树状结构(父子)存在的,当孩子元素被点击时,会发生哪些情况呢?
这些情况,我们原来都没怎么关注,因为我们写前端代码的量并不多,仅仅做表单元素处理等,但是纯粹的 前端开发者都需要考虑上边所述的情况,Vue 提供了几个修饰符,来帮助我们控制 事件冒泡 及一些更为细化的事件触发。
概念:事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如 onclick 事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到 document/window,冒泡过程结束。
在 Vue 中如何解决冒泡事件呢?我们使用“.stop”来阻止事件向上级传递。
任务 6:阅读下边的代码,验证.stop 阻止事件的向上传递。
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">script>
<style type="text/css">
div{
border: 1px solid red;
}
span{
border: 2px solid blue;
}
style>
head>
<body>
<div id="app">
<div @click="wai()">
外层div
<span @click="nei()">内层spanspan>
div>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
methods:{
wai: function(){
console.log("wai");
},
nei: function(){
console.log("nei");
}
}
})
script>
body>
html>
.prevent 修饰符的作用是取消事件的默认动作。用于拥有默认动作的 html 标签,例如:、标签等。
任务 7:验证通过 prevent 取消默认动作的功能。
<div id="app">
<a href="https://www.baidu.com" @click.prevent="">跳转a>
div>
事件冒泡的默认顺序是由内到外,使用“.capture”修饰符可以使事件的触发顺序变为由外到内。
任务 8:验证通过 capture 修饰符来改变事件冒泡的顺序。
<div id="app">
<div @click.capture="wai()">
外层div
<span @click="nei()">内层spanspan>
div>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
methods:{
wai: function(){
console.log("wai");
},
nei: function(){
console.log("nei");
}
}
})
script>
.self 修饰符只会触发元素本身的事件,事件不从内部的子孙元素触发。 即:event.target 是当前元素本身时才会触发事件。
任务 9:自己编写代码验证 self 修饰符,阻断事件冒泡。
<div id="app">
<div @click.self="wai()">
外层div
<span @click="nei()">内层spanspan>
div>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
methods:{
wai: function(){
console.log("wai");
},
nei: function(){
console.log("nei");
}
}
})
script>
.once 修饰符:元素所绑定的事件仅触发 1 次。
任务 10:验证.once 修饰符的功能。
<div id="app">
<div @click="wai()">
外层div
<span @click.once="nei()">内层spanspan>
div>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",//可以是 css 选择器.例如: #app 或.app
data: {
},
methods:{
wai: function(){
console.log("wai");
},
nei: function(){
console.log("nei");
}
}
})
script>
事件修饰符可以叠加使用。例如:
任务 11:下边的代码,实现了修饰符的叠加,运行测试一下吧。
<a v-on:click.stop.prevent="doSome">a>
**组件(可复用的代码段)**是 vue 最强大的功能之一,是可扩展的 html 元素,是封装可重用的代码,同 时也是一个可以放重复使用的 Vue 实例。
定义和使用组件,通常情况下我们会:使用 Vue.component
方法,来定义(注册)组件,然后就可以在 Vue 的 环境中使用了。
语法:
Vue.compontent("标签名",{})
任务1:实现1个自己记录自己被点击次数的组件按钮。
<div id="app">
<cli-btn>cli-btn>
div>
<template id="temp">
<button @click="cli()">{{msg}}button>
template>
<script type="text/javascript">
//标签名字随便写,但是不能包含大写字母,必须都为小写,否则会报错。
Vue.component("cli-btn",{
template:"#temp",
//模板里的data必须定义成方法,固定格式
data:function(){
return{
n:0,
msg:"请点击"
}
},
//方法还和原来一样。
methods:{
cli(){
this.msg = "您已经点击了"+this.n+++"下";
}
}
})
//最后需要创建Vue实例来进行渲染,必须放到最后才行。
var app = new Vue({
el:"#app"
})
script>
标签名字随便写,但是不能包含大写字母,必须都为小写,否则会报错。
任务 2: 去掉 id="temp"的 template,将其内容,以字符串的方式,放到 Vue.component 函数的 template 属性中,并最终将组件封到1个 js 文件中。
创建js文件,把组件代码剪切进去,然后在主页面上引用js文件,js文件:
//标签名字随便写,但是-后面第一个字母不能为大写,像cli-Btn,会报错。
Vue.component("clibtn",{
template:``,
//模板里的data必须定义成方法,固定格式
data:function(){
return{
n:0,
msg:"请点击"
}
},
//方法还和原来一样。
methods:{
cli(){
this.msg = "您已经点击了"+this.n+++"下";
}
}
})
主页面引用js文件进行测试
DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="js/vue.min.js" type="text/javascript" charset="utf-8">script>
<script src="js/compontent.js" type="text/javascript" charset="utf-8">script>
head>
<body>
<div id="app">
<clibtn>clibtn>
div>
<script type="text/javascript">
var app = new Vue({
el:"#app"
})
script>
body>
html>
通常情况下,我们可以将多个组件写到 1 个 js 文件中,作为基础组件库,在注册组件的时候,都需要一个 名字(以便后期使用)。
调用 Vue 的内置函数 component 来注册一个全局组件:Vue.component(‘component-name’,{…}),其中 component 函数的第一个参数就是组件的名字,依据 W3C 规范自定义组建的名字应当避免与现有标签或未来会出现的标签名字重复。推荐使用全小写字母且必须包含一个’-'连接符。
全局注册在所有的 Vue 实例中都可以使用,全局注册使用 Vue.component 函数注册,我们在入门的例子中, 已经给大家展示过。
局部注册的组件只能在 vue 实例内部使用,这里只给大家点到为止,因为在日常开发中,大多数都是使用全 局注册。
每个组件在被创建时,调用 data 函数时将返回 data 对象的一个新的实例。如果 data 是 JavaScript 对象, 则会返回该对象的引用(当 data 对象中的属性发生变化时,会影响到所有的该 Vue 组件的实例)。
上面代码中组件的data函数,自行理解。
在注册组件时,通过 props 可以定义参数,这些参数是组件内部 和 使用组件者 沟通的桥梁,就像 js 中 方法的参数一样(调用者可以传递参数到方法中,方法内部可以用这些参数)。
可以理解为传递给组件的参数。使用 props 定义组件可接收的参数名,props 可定义参数类型和参数有效值等。
任务5: 阅读下面案例,思考参数的传递。
<div id="app">
<news-item :news_title="news.title" :news_content="news.content">news-item>
div>
<template id="temp">
<div>
<h3 v-text="news_title">h3>
<p v-text="news_content">p>
div>
template>
<script type="text/javascript">
Vue.component('news-item',{
template:"#temp",
//定义桥梁,用来在标签中引用vue实例中data的数据,有两种写法,下面会讲另一种
props:['news_title','news_content']
})
var app = new Vue({
el:"#app",
data:{
news: {
title: "新闻标题",
content: "就在美国对中国发动贸易战几个小时后,美国贸易代表处却在今日北京时间凌晨三点宣布说,那些会被贸易战影响的从中国进口产品的美国企业,可以有90天的时间向美国政府申请有效期为1年的“关税豁免”"
}
}
})
script>
结果:
props里也可以这样写
props:['news-title','news-content']
这样写的话,div里要这样写:news-title,在这里用newsTitle调用。
<news-title :newsTitle="news.title" :newsTontent="news.content">news-title>
prop 的类型可以是 Number 、Boolean 、Function、Object。
任务6:点击a标签,跳转页面的路径中要出现正确的路径拼接
<div id="app">
<news-item :news_id="news.id" :news_title="news.title" :news_content="news.content">news-item>
div>
<template id="temp">
<div>
<a :href="'/home/'+news_id">
<h3 v-text="news_title">h3>
a>
<p v-text="news_content">p>
div>
template>
<script type="text/javascript">
Vue.component('news-item',{
template:"#temp",
//props定义数据的数据类型
props:{
"news_id":Number,
"news_content":String,
"news_title":String
}
})
var app = new Vue({
el:"#app",
data:{
news: {
id:"123",
title: "新闻标题",
content: "就在美国对中国发动贸易战几个小时后,美国贸易代表处却在今日北京时间凌晨三点宣布说,那些会被贸易战影响的从中国进口产品的美国企业,可以有90天的时间向美国政府申请有效期为1年的“关税豁免”"
}
}
})
script>
要注意标蓝色的超链接代码 的参数拼接,双引号中套单引号,要理解透彻;
标红的参数类型,虽然可以指定,但无法真正起到限制作用,当我们给 1 个字符串时(比如:将 10 变 为 abc),只会在控制台中给你1个错误提示,如:
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会 在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。 为了定制 prop 的验证方式,你可以为 props中的值提供:
默认值
验证
语法示例:
props: {
//基础的类型检查 (null 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组且一定会从一个工厂函数返回默认值
default: function() {
return {
message: 'hello'
}
}
},
// 自定义验证函数
propF: {
validator: function(value) {
// 这个值必须匹配下列字符串中的一个
return [
'success',
'warning',
'danger'
].indexOf(value) !== -1
}
}
}
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
注意:那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性(如 data、computed 等)在 default 或 validator 函数中是不可用的。
任务 7:阅读下边代码,体会默认值和验证的使用。
<div id="app">
<news-item :news_id="news.id" :news_title="news.title" :news_content="news.content">news-item>
div>
<template id="temp">
<div>
<a :href="'/home/'+news_id">
<h3 v-text="news_title">h3>
a>
<p v-text="news_content">p>
div>
template>
<script type="text/javascript">
Vue.component('news-item',{
template:"#temp",
//props定义数据的数据类型
props:{
"news_id":{
//默认值
default:222
},
//没有任何限制约束
"news_content":{},
//自定义验证、标题字数不能小于4个字
"news_title":{
validator: function(val){
return val.length >= 4;
}
}
}
})
var app = new Vue({
el:"#app",
data:{
news: {
title: "新闻标题",
content: "就在美国对中国发动贸易战几个小时后,美国贸易代表处却在今日北京时间凌晨三点宣布说,那些会被贸易战影响的从中国进口产品的美国企业,可以有90天的时间向美国政府申请有效期为1年的“关税豁免”"
}
}
})
script>
组件实例的作用域是孤立的。这意味着不能(也不应该)在子组件的模板内直接引用父组件的数据。
要让子组件使用父组件的数据,我们需要通过子组件的 props 选项。 prop 是单向绑定的:当父组件的属性 变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。 每次父组件更新 时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变prop。
<div id="app">
<news-item v-bind:news_id="news.id" v-bind:news_title="news.title" v-bind:news_content="news.content">news-item>
<news-item v-bind:news_id="news.id" news_title="干翻老美" v-bind:news_content="news.content">news-item>
<news-item v-bind:news_id="news.id" v-bind:news_title="news.title" v-bind:news_content="news.content.substring(0,20)+'...'">news-item>
<news-item v-bind:news_id="120+10" v-bind:news_title="news.title" v-bind:news_content="news.content">news-item>
div>
<template id="temp">
<div>
<a :href="'/home/'+news_id">
<h3 v-text="news_title">h3>
a>
<p v-text="news_content">p>
div>
template>
<script type="text/javascript">
Vue.component('news-item', {
template: "#temp",
//props定义数据的数据类型
props: {
"news_id": {
//默认值
default: 222
},
//没有任何限制约束
"news_content": {},
//自定义验证、标题字数不能小于4个字
"news_title": {
validator: function(val) {
return val.length >= 4;
}
}
}
})
var app = new Vue({
el: "#app",
data: {
news: {
title: "新闻标题",
content: "就在美国对中国发动贸易战几个小时后,美国贸易代表处却在今日北京时间凌晨三点宣布说,那些会被贸易战影响的从中国进口产品的美国企业,可以有90天的时间向美国政府申请有效期为1年的“关税豁免”"
}
}
})
script>
父组件如何向子组件传递模板内容,大家有没有什么解决方法?
对于这个需求,Vue 提供一种快捷便利的操作—slot 插槽标签。slot 插槽可以在组件中实现预留位置,方 便在父组件调用时向子组件指定位置传递不同内容,显示不同效果。
基本语法如下:
template:`
插槽默认内容
`
在使用时,需要在组件标签内部编写要传递的内容。父组件的内容会替换 slot 的默认值,如果不传递内容, 会显示子组件 slot 插槽默认内容。
<组件名>内容组件名>
<组件名>内容组件名>
<组件名>组件名>
任务 1:根据插槽语法,编写一个程序员必读书籍的插槽效果。
<div id="app">
<test-slot>《MySql从入库到跑路》test-slot>
div>
<script type="text/javascript">
Vue.component('test-slot',{
template:`
程序员必读书籍:《Java从入门到入土》
`
})
new Vue({
el:"#app"
})
script>
如果一个组件内有多个插槽,我们该给指定插槽传递内容那?
有时我们需要多个插槽。例如对于一个带有如下模板组件:
<div id="app">
<test-slot>
test-slot>
div>
<script type="text/javascript">
Vue.component('test-slot',{
template:`
程序员必读书籍:《Java从入门到入土》
程序员必看电影:《黑客帝国》
程序员必会技能:《Ctrl+C Ctrl+v》
`
})
new Vue({
el:"#app"
})
script>
我们想要对插件选择然后赋值显示,这样就没办法了,但是slot标签提供了一个name属性,我们可以根据name属性进行插值
<div id="app">
<test-slot>
<template v-slot:book>《MySql从入库到跑路》template>
<template v-slot:movie>《社交网络》template>
<template v-slot:skill>《开关机》template>
test-slot>
div>
<script type="text/javascript">
Vue.component('test-slot',{
template:`
程序员必读书籍:《Java从入门到入土》
程序员必看电影:《黑客帝国》
程序员必会技能:《Ctrl+C Ctrl+v》
`
})
new Vue({
el:"#app"
})
script>
跟 v-on 和 v-bind 一样,v-slot 也有缩写,可以把 v-slot: 替换为字符 #。
例如:v-slot:header 可以被重写为 #header
<div id="app">
<test-slot>
<template #book>《MySql从入库到跑路》template>
<template #movie>《社交网络》template>
<template #skill>《开关机》template>
test-slot>
div>
<script type="text/javascript">
Vue.component('test-slot',{
template:`
程序员必读书籍:《Java从入门到入土》
程序员必看电影:《黑客帝国》
程序员必会技能:《Ctrl+C Ctrl+v》
`
})
new Vue({
el:"#app"
})
script>
在前面的学习的传统的组件中存在以下问题:
针对传统组件的问题,Vue 提供了一个解决方案——使用 Vue 单文件组件。单文件组件的文件扩展名为.vue。 文件内部组成结构包含三个部分:
下面是一个文件名为 Hello.vue 的简单实例:
通过单文件组件,我们可以升级组件代码,构建简洁和功能更丰富的组件,提高生产力。但是大家会很好奇, 为什么单文件组件在 HTML 页面使用那么很不方便,我们还要学习。因为在企业项目开发中,它运用场景更多是 在 Vue 脚手架项目结构中。
解释script内的代码:
原代码
<script>
Vue.extend({
name:"vue-test",
data(){
return {
msg: "Vue单文件组件真香"
}
}
})
</script>
导出时候的代码【Vue.extend()可以省略】:
<script>
export default {
name:"vue-test",
data(){
return {
msg: "Vue单文件组件真香"
}
}
)
</script>
Vue-devtools
是生态中不可获取的一部分,是开发过程中必不可少的 Vue 的调试神器,主要用于调试观察 组件之间的数据参数动向,其高效、简洁、方便的特点可以极大程度的提高我们的开发效率,深受 vue 开发者的 喜爱。这里使用 Chrome 浏览器进行安装、配置和调试为主。
Vue-devtools 安装有两个主流方式,一种是官方方式,较为复杂繁琐,一种是使用市面上封装安装包,操 作简单明了。这里以后一种为主,前一种安装方式大家可以在扩展中自学。
Vue-devtools 安装与使用步骤具体操作如下:
谷歌浏览器搜拓展迷
,或点击网址:https://www.extfans.com/all/搜索vue或devtools
进行下载。
安装好以后,为压缩包
这时候我们点击chrome的右上角省略号,点击更多程序->扩展程序,就会进入如下页面(默认为空)。
这时候我们把压缩包直接拉进里面就可以了,如果不行的话,就解压了再拉进去
这时候我们就添加成功了。
如果出现chrome无法从该网站添加应用、扩展程序和用户脚本
提示,那么我们打开一个新的标签页,打开这个路径:chrome://flags/#extensions-on-chrome-urls,把第一个的值Disabled改为Enabled重启浏览器就可以了
添加成功以后,我们可以编写一个简单的vue测试,然后用chrome浏览器打开
<div id="app">
{{n}}
<button type="button" @click="add()">+button>
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
n:1
},
methods:{
add(){
this.n++;
}
}
})
script>
浏览器打开后,我们按F12打开“开发者模式”,找到vue。
在这里面就可以对vue进行调试操作了。
Vue-CLI 是 Vue 官方提供的一种基于 Vue.js 进行快速开发的完整系统,可以快速搭建 Vue 的项目模板。 使用 Vue 脚手架开发项目有以下好处:
为什么安装 Node?
因为 Vue 脚手架的安装、启动、打包和后续项目中插件的安装都这里需要 node 的其中的 npm 包管理工 具。可以说 Node.js 是 Vue-CLI 开发的基石。
在日常项目开发中,npm有以下的常见使用场景:
官网下载 Node.js 安装包: 下载 | Node.js 中文网 (nodejs.cn)
安装,基本无脑下一步
安装完毕,测试node
配置 npm 下载插件的默认安装目录和缓存日志目录
注意:因为有的同学电脑权限不足,可以提前先做安装目录中创建 node_global 和 node_cache 文件夹。
打开 cmd 窗口,依次输入配置命令,盘符自己选。
配置 node 所需环境变量
安装国内淘宝镜像
我们通过 npm 命令下载 node 插件的时候因为访问的是国外网站,所以可能会出现下载的很缓慢或者干脆是直 接下载失败,在这种情况下,我们可以通过配置国内镜像来解决,一般配置的是淘宝 npm 镜像 cnpm。
安装命令:
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm -v
脚手架安装命令
如果出现外部指令什么的,我们需要关闭原来命令提示符,然后再打开,因为我们配置环境变量后,需要重新启动这个才能有用
到这为止,Vue 脚手架已经安装完成了。但是有两个概念需要区分开:
Vue 脚手架创建项目有两种,一种是命令行创建方式,一种是图形化界面方式。
第一种命令行创建方式:
第二种图形化界面创建方式:
我们开始解析 Vue 脚手架项目的项目结构,熟悉结构才能更快速的开发。
通过上边的操作,大家会有一个感觉,Vue 脚手架项目并不是那么难。当然也需要我们不断的去熟悉项目结构。
在组件开发章节中,我们已经学习了组件的使用和组件之间进行数据的传递,这里我们做一下简单回顾:
需要清楚的认识到,这三种方式不仅仅操作繁琐,而且比较适合于小范围内的数据共享,如果 Vue 应用程序 的数据共享数据需要大范围、使用比较频繁的话,这三种方式就有些捉襟见肘了。Vue 提供了一套较为成熟的解决方案------Vuex。
在官方定义中,Vuex 是一个专门服务 Vue.js 应用程序的状态(数据)管理模式。它采用集中式存储管理应 用的所有组件的状态(数据),可以方便的实现组件之间的数据的共享。下图是 Vue 官方给出的 Vuex 理念示意图。
思考:什么是状态(数据)管理模式?如何把握住图中每个点表示的含义?
所谓状态(数据)管理模式,简单的说就是,将多个组件(Vue Components)共享的变量全部存储在一个对 象里面。然后,将这个对象放在顶层的 Vue 实例中,让全局下的其他组件可以使用,多个组件就可以实现共享这 个对象中的所有变量属性。
状态管理模式就是数据管理模式,Vuex 就是一个提供可以在多个组件间共享状态的插件,它可以理解为是 Vue 的数据库,可以存储全局的共享数据,总之就一句话,用它就对了。
我们用下图来对比一下,Vuex 和之前学习的三种方式之间的区别。
思考:什么类型的数据适合存储到 Vuex 中?
一般情况下,只有组件之间共享的数据,才有必要存储到 Vuex 中;对于组件中的私有数据,依旧存储在组件自 身的 data 中即可。当然,在实际开发中,我们需要具体情况具体分析。
这里我们采用的 Vue 脚手架项目开发,根据以下情况来完成 Vuex 的初始化。
我们这里只演示创建项目时安装。
我们使用vue ui
命令创建项目,在项目所在文件夹cmd然后输入命令。
然后就会自动打开可视化视图。
我们这里选择创建->在此创建项目。
输入项目名称
我们这里选择手动配置项目
打开vuex配置,然后点击下一步
进行配置,然后创建项目
把配置保存为预设
项目创建成功后,我们把项目运行
启动App
启动完后,我们把项目导入到Hbuilder中,可以发现,比普通的CLI项目多了几个文件
到目前为止,就代表创建成功了。如果创建项目的时候出现Cannot read properties of undefined (reading 'indexOf')
报错,那么我们就更换网络重新创建,大部分都是网络问题。
Vuex的核心概念有以下几个:
state 是 Vuex 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 对象的 State 中进行存储,State 是一个“唯一数据源”。
//创建 store 数据源,提供唯一公共数据访问渠道
export default new Vuex.Store({
//State 提供唯一的公共数据源,统一存放所有共享数据
state: {
//该数据将全局共享
数据变量名 : 值
}
})
注意,在 state 中:
接下来,我们会通过一个全局的案例来串联四个常用属性。
案例示意图如下:
在 components 中创建 AddComponent 组件
全局变量num的值为:??
在 components 中创建 SubComponent 组件
全局变量num的值为:??
在 App.vue 页面使用 AddComponent 和 SubComponent 组件
注意:在使用其他组件时,不要忘了导入、注册后再使用
打开store文件夹下index.js文件,改造代码
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
num:0
},
getters: {},
mutations: {},
actions: {},
modules: {},
});
把数据放到共享文件夹上了,其他文件就要读取数据了,读取的数据有两种:
组件访问 state 中数据的第一种方式:
this.$store.state.全局数据名称
组件访问 state 中数据的第二种方式:使用 mapState 函数
第一步:按需从Vuex中导入mapState函数
import {mapState} from 'vuex'
//注意 vuex 全小写 mapState 是小驼峰命名方式
第二步:映射 mapState 为 computed 计算属性, 需要将刚才导入的 mapState 函数,映射为当前组件的 computed 中的计算属性,将需要的全局数据注入到当前组件中。
computed:{
...mapState(['数据变量名 1','数据变量名 2'])
}
注意:这里的…是展开运算符,会将组件需要的全局数据映射为当前组件的计算属性。简单来说,通过这一步 操作,可以将 state 的数据复制到计算属性中,我们就可以在组件中使用了。
使用第一种方法改造AddComponent组件
全局变量num的值为:{{ $store.state.num }}
这时候我们打开网页,查看效果,看看是否引入成功(如果报错,请查看[取消运行时代码检查]那一节)
SubComponent组件使用第二种方式改造
全局变量num的值为:{{ num }}
SubComponent组件也进行修改后,结果如下:
数值已经显示出来了,接下来该按钮的点击事件了。
Mutation 对象是 Vuex 对象中,唯一可以直接修改 state 的数据的对象
语法如下:
//创建 store 数据源,提供唯一公共数据访问渠道
export default new Vuex.Store({
//State 提供唯一的公共数据源,统一存放所有共享数据
state: {
//该数据将全局共享
数据变量名 : 值
},
mutations: {
//用于全局的事件处理函数
//函数的第一个形参是 state,用于方便调用 state 数据
//其他参数 n 放置在 state 后面
mu1(state){//函数体},
mu2(state,n){ //函数体}
}
})
注意:
按钮点击功能实现如下:
根据 mutations 基本用法,创建 num 变量加一和加 N 还有减一的操作。
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
num: 0,
},
getters: {},
mutations: {
addNum(state){
state.num++;
},
addNumN(state,n){
state.num += n;
},
subNum(state){
state.num--;
}
},
actions: {},
modules: {},
});
方法定义好以后,我们需要在其他组件中调用mutations
里写好的方法,调用的方法有两种,这里一个组件里用一种方法。
Vuex 提供了两种调用 mutations 中方法的方式。
调用 mutations 中方法的第一种方式:在组件的方法中直接使用
this.$store.commit('函数',参数);
调用 mutations 方法的第二种方式:使用 mapMutations 函数
第一步按需从 Vuex 中导入 mapMutations 函数
import {mapMutations} from 'vuex'
第二步、映射 mapMutations 函数映射为组件的 methods 中的方法 需要将刚才导入的 mapMutations 函数,映射为当前组件的 methods 中的方法,将需要使用的方法注入到当前组件中。
methods:{
...mapMutations(['函数 1','函数 2']),
事件函数(){
//直接调用映射的函数
this.函数 1(参数);
}
}
注意:
使用第一种方法在AddComponent
组件中调用方法
全局变量num的值为:{{ $store.state.num }}
在AddComponent组件中调用addNumN()
方法
全局变量num的值为:{{ $store.state.num }}
全局变量num的值为:{{ $store.state.num }}
使用第二种方式实现num--
按钮的点击事件
全局变量num的值为:{{ num }}
在日常开发过程中,会从服务器端异步请求获取当然组件全局操作的数据。也意味着 state 中的数据并非一开始 设定好的,而是需要异步请求后再设置的。Vuex 提供专门用于异步操作的对象 Action
Action 是专门用于处理异步任务的,例如:异步数据请求、定时任务等。如果需要异步操作变更数据,必须通 过 Action,而不能直接使用 Mutation 或者 State。
而且重点是,在 Action 中对 State 的操作仍然需要通过触发 Mutation 方法的来变更数据。
注意:
Action基本语法:
actions:{
异步函数(context,param){
//调用 mutations 中的方法
context.commit('mutation 方法',参数)
}
}
注意:
在 actions 中,不能直接修改 state 中的数据,必须使用 mutations 对象中的方法。
context 参数是为了方便调用 mutations 中的方法,调用异步操作方法时不需要传。
param 是调用异步操作方法需要传入的参数,可以是基本值(数字、字符串、布尔值等)、数组、对象等, 参数名可以自定义。
根据 actions 基本用法,使用定时器模拟异步任务,完成三秒之后 num 变量加 N 操作
在actions中编写倒计时修改num的值
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
num: 0,
},
getters: {},
mutations: {
addNum(state) {
state.num++;
},
addNumN(state, n) {
state.num += n;
},
subNum(state) {
state.num--;
},
},
actions: {
asyncAdd(context,n){
setTimeout(()=>{
context.commit("addNumN",n);
},3000)
}
},
modules: {},
});
Vuex 提供了两种调用 actions 中异步方法的方式。
调用 actions 中方法的第一种方式:在组件的方法中直接使用
this.$store.dispatch('异步函数名',参数);
调用 actions 方法的第二种方式:使用 mapActions 函数
第一步按需从 Vuex 中导入 mapActions 函数:
import {mapActions} from 'vuex'
第二步、映射 mapActions 函数映射为组件的 methods 中的方法: 需要将刚才导入的 mapActions 函数,映射为当前组件的 methods 中的方法,将需要使用的方法注入到当前组件中。
methods:{
...mapActions(['函数 1','函数 2']),
事件函数(){
//直接调用映射的函数
this.函数 1(参数);
}
}
注意:这里的操作同 mapMutations 操作类似,就不赘述了。
在AddComponent
组件中调用定义的异步倒计时(使用第一种方式)
全局变量num的值为:{{ $store.state.num }}
全局变量num的值为:{{ $store.state.num }}
第二种方法就不再演示了,和上面一样。
Getter 用于对 Store 中的数据进行加工处理形成新的数据;
定义Getter:
getters:{
包装函数(state){
return '对 state 参数包装后的内容'
}
}
注意:
根据 getters 基本用法,将页面中的“当前全局参数 num 的值是:”改造成 getter 写法。
在getters中添加方法,返回内容
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
num: 0,
},
getters: {
getNum(state){
return "全局参数num变量的值为:" + state.num;
}
},
mutations: {
addNum(state) {
state.num++;
},
addNumN(state, n) {
state.num += n;
},
subNum(state) {
state.num--;
},
},
actions: {
asyncAdd(context, n) {
setTimeout(() => {
context.commit("addNumN", n);
}, 3000);
},
},
modules: {},
});
Vuex 提供了两种调用 getters
调用 getters 中方法的第一种方式
this.$store.getters.包装函数名;
调用 getters 方法的第二种方式:使用 mapGetters 函数:
第一步按需从 Vuex 中导入 mapGetters 函数
import {mapGetters} from 'vuex'
第二步、映射 mapGetters 函数映射为 computed 计算属性,需要将刚才导入的 mapGetters 函数,映射为当前组件的 computed 中的计算属性,然后就可以在组件中直接 使用了。
computed:{
...mapGetters(['函数 1','函数 2'])
}
注意:这里的操作同 mapState 操作类似,就不赘述了。
分别在AppComponent和SubComponent中调用getters中方法
(此处都用第一种方式调用)
{{$store.getters.getNum}}
{{$store.getters.getNum}}
当我们修改getters方法中的返回值时,这三个组件显示的内容将都会一起改变。
本章主要学习 Vuex 状态管理的基本操作。主要学习了 Vuex 的安装、配置和 Store 对象中的四大属性 State、 Mutation、Action、Getter 创建和调用。其中我们可以将四个属性分为两类:
1、 数据的基本操作
2、方法的基本操作
当我们写完代码想要在页面查看效果的时候,会发现仪表盘报错,像如下这样:
这是因为创建项目的时候,默认开启了代码自动检查功能,有时候不是代码的错误,可能因为格式的错误报错不显示,很麻烦,有三种解决办法:
修改完配置后,我们必须重新运行才能生效
line on serve
选项了。 在网络发达的现在,我们可以使用电脑、手机等多种电子设备,打开浏览器,浏览不同网站,访问网站的各 位链接信息。就在访问、操作网站的过程中,我们就在无形的使用路由这个技术。路由就是指根据不同的页面 URL 请求,分配到对应的处理程序的技术。
通常,路由分为前端路由和后端路由:
可以发现,不管是后台路由还是前端路由,都是一种映射关系
Vue Router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
SPA 单页面应用指的是,整个网站只需要有一个页面,当 Vue 感知 URL 变化时,会动态的把当前的页面内容 清除掉,再把下一个页面的内容挂载到页面上。此时的路由就不是后端来做了,而是前端来做,判断页面到底显 示哪一个组件,再把以前的组件清除掉使用新的组件。就不会每一次跳转都请求 HTML 文件。
Vue 实现的单页面应用,页面组件片段切换快,用户体验好。
依旧和上面一样,在vue项目文件夹路径输入cmd
输入vue ui
使用可视化创建项目的时候导入vue Router
就可以使用了。
创建项目的时候选择Router
选项。
选择和上面步骤一样的配置,这里关闭代码检查。
运行项目,启动app
启动后,我们把项目导入到Hbuilder
中,进行编辑,可以发现我们项目中多了些文件。
到此为止我们项目创建就完成了。
我们首先随便找两张图片放到assets
文件夹中
在views
文件夹里分别创建ChengShiComponent、XingKongComponent
两个组件,内容如下:
另一个组件也一样,只不过图片和name值不一样,这里就不展示了。
编写完两个组件后,我们在router->index.js
文件里配置路由。
import Vue from "vue";
import VueRouter from "vue-router";
//这个是自带的,没用,我们删掉就可以了。
//import HomeView from "../views/HomeView.vue";
//导入资源
import ChengShiComponent from "../views/ChengShiComponent.vue";
import XingKongComponent from "../views/XingKongComponent.vue";
Vue.use(VueRouter);
const routes = [
// 配置资源路径,path:路径 component:导入的组件名 还有name属性,后面会讲
{
path: "/chengshi", // 第一路径前面必须带/
component: ChengShiComponent,
},
{
path: "/xingkong", // 第一路径前面必须带/
component: XingKongComponent,
}
];
const router = new VueRouter({
routes,
});
export default router;
配置完路径后,我们就需要修改App.vue
文件进行调用路由
编写完App.vue
文件后,我们就可以回到页面查看结果了。
点击城市或者星空的时候,下面就会显示对应的照片
这时候,我们发现图片太大,看起来很麻烦,这时候我们可以修改图片样式
在App.vue
文件内下面的style内,添加图片样式就可以了。
img {
width: 50%;
height: 50%;
}
当我们点击不同的a标签的时候,下面的图片会改变,路径也会进行改变,路径就是我们在路由内设置的path
值
页面打开时,其实也是有一个链接地址\
,现在我们希望默认地址可以指向其他链接,要实现这个功能, 我们需要用到路由重定向。路由重定向指的是,用户在访问地址 A 的时候,强制用户跳转到地址 B,从而展示特定的组件页面。
Vue 实现路由重定向是通过路由规则中的redirect 属性
,为 path 指定一个新的路由地址,这样就完成了 路由重定向的设置。
routes: [
{path : '/A 地址',redirect : '/B 地址'},
{path : '/B 地址', component : 'B 组件'}
]
任务1:实现打开网页默认显示城市图片,访问城市的路由,代码如下:
import Vue from "vue";
import VueRouter from "vue-router";
//这个是自带的,没用,我们删掉就可以了。
//import HomeView from "../views/HomeView.vue";
//导入资源
import ChengShiComponent from "../views/ChengShiComponent.vue";
import XingKongComponent from "../views/XingKongComponent.vue";
Vue.use(VueRouter);
const routes = [
// 配置资源路径,path:路径 component:导入的组件名 还有name属性,后面会讲
{
// /为默认路径 redirect为重定向,意思为当访问localhost:8080的时候,会默认访问'/chengshi'路由,显示城市图片
path: "/",
redirect: "/chengshi",
},
{
path: "/chengshi", // 第一路径前面必须带/
component: ChengShiComponent,
},
{
path: "/xingkong", // 第一路径前面必须带/
component: XingKongComponent,
}
];
const router = new VueRouter({
routes,
});
export default router;
在前面的章节中,我们学习了组件的开发和应用。在实际应用开发界面,通常由多层嵌套的组件组合而成。 比如,我们登录组件中,需要嵌套着立即注册和忘记密码操作。
这里就需要使用到 Vue 路由中的嵌套路由操作,嵌套路由指的是通过路由规则的层级嵌套,可以在页面上展示出复杂的组件结构关系。
嵌套路由需求分析:
实现思路:
代码步骤:
第一步:在父路由规则中,通过 children 属性,添加子路由规则
routes: [
{
path : '/父 path 地址', component : 父组件,
//children 数组表示子路由规则
children : [
{path : '/子 path 地址 1',component : 子组件 1},
{path : '/子 path 地址 2',component : 子组件 2}
]
}
]
第二步:在父路由组件中添加子路由链接和路由占位符
<template>
<div>
<img src="../assets/1.jpg" />
<br />
<!-- 路径一定要包含父路由的路径,要完整 -->
<router-link to="/父路由/子路由">a标签内容</router-link> |
<router-link to="/父路由/子路由">a标签内容</router-link>
<!-- 显示引用路由的位置 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "ChengShiComponent",
};
</script>
<style></style>
任务1:优化原代码,当点击城市的时候,在图片下方会出现一样的两个超链接,点击下方任意一个分类,下面会对应出现每个城市的分类。
创建HeNanComponent.vue
组件,代表河南城市的分类
- 郑州
- 洛阳
- 安阳
- 商丘
- 周口
- 信阳
创建HeBeiComponent.vue
组件,代表河北城市分类
- 石家庄
- 秦皇岛
- 邯郸
- 邢台
- 保定
- 张家口
编写完组件后,我们就可以在router->index.js
中进行这两个组件的路由配置
import Vue from "vue";
import VueRouter from "vue-router";
//这个是自带的,没用,我们删掉就可以了。
//import HomeView from "../views/HomeView.vue";
//导入资源
import ChengShiComponent from "../views/ChengShiComponent.vue";
import XingKongComponent from "../views/XingKongComponent.vue";
import HeNanComponent from "../views/HeNanComponent.vue";
import HeBeiCompanent from "../views/HeBeiCompanent.vue";
Vue.use(VueRouter);
const routes = [
// 配置资源路径,path:路径 component:导入的组件名 还有name属性,后面会讲
{
// /为默认路径 redirect为重定向,意思为当访问localhost:8080的时候,会默认访问'/chengshi'路由,显示城市图片
path: "/",
redirect: "/chengshi",
},
{
path: "/chengshi", // 第一路径前面必须带 /
component: ChengShiComponent,
// 子组件路由配置
children:[
{
path: "henan", // 第二路径前面不要带 /
component: HeNanComponent
},
{
path: "hebei", // 第二路径前面不要带 /
component: HeBeiComponent
}
]
},
{
path: "/xingkong", // 第一路径前面必须带 /
component: XingKongComponent,
}
];
const router = new VueRouter({
routes,
});
export default router;
配置完路由以后,我们就可以在ChengShiComponent.vue
组件中添加router-link
标签引用了
河南 |
河北
这时候我们就可以在页面上测试预览了
至此,我们任务就完成了。
注意:
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在执行路由跳转、路由链接或者路由传参的 时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
语法: 在 routes 配置中使用 name 关键字进行命名
routes: [
{
path : '/path 地址',
name : '路由的 name',
component : 组件
}
]
调用路由
调用路由分为编程式导航
调用路由的方法和声明式导航
调用路由的方法,编程式导航下面会讲,声明式导航上面用到的
这种直接当做a
标签引用的被称为声明式导航。
声明式路由调用方法有三种:
第一种
//第一种
<router-link to="/path 地址">提示文字</router-link>
第二种
//第二种:使用 path 关键字
<router-link :to="{path : 'path 地址'}">提示文字</router-link>
第三种
//第三种:使用 name 关键字
<router-link :to="{name : 'name 属性值'}">提示文字</router-link>
注意:
/
/
,而且需要使用:to
,进行路径编译编程式导航调用路由也有三种方法,和这个大体上差不多,下面会讲。
任务1:优化原代码,给两个子路由添加name
值,使调用子路由的时候,路径可以不写那么长
打开router->index.js
文件,在两个子路由对象内添加name
属性。
import Vue from "vue";
import VueRouter from "vue-router";
//这个是自带的,没用,我们删掉就可以了。
//import HomeView from "../views/HomeView.vue";
//导入资源
import ChengShiComponent from "../views/ChengShiComponent.vue";
import XingKongComponent from "../views/XingKongComponent.vue";
import HeNanComponent from "../views/HeNanComponent.vue";
import HeBeiComponent from "../views/HeBeiComponent.vue";
Vue.use(VueRouter);
const routes = [
// 配置资源路径,path:路径 component:导入的组件名 还有name属性,后面会讲
{
// /为默认路径 redirect为重定向,意思为当访问localhost:8080的时候,会默认访问'/chengshi'路由,显示城市图片
path: "/",
redirect: "/chengshi",
},
{
path: "/chengshi", // 第一路径前面必须带 /
component: ChengShiComponent,
// 子组件路由配置
children: [
{
path: "henan", // 第二路径前面不要带 /
component: HeNanComponent,
//添加name属性,用处和path一样
name: "hn"
},
{
path: "hebei", // 第二路径前面不要带 /
component: HeBeiComponent,
//添加name属性,用处和path一样
name: "hb"
},
],
},
{
path: "/xingkong", // 第一路径前面必须带 /
component: XingKongComponent,
},
];
const router = new VueRouter({
routes,
});
export default router;
打开ChengShiComponent.vue
组件,修改中to的值
河南 |
河北
Vue 路由中页面导航的两种方式:
Vue 实现编程式导航
常见 Vue 路由编程式导航 Api 如下:
这里我们以第一种 push 方式为重点进行学习
语法如下:
//第一种
this.$router.push('路由配置的 path 地址');
//第二种:使用 path 关键字
this.$router.push({path : '路由配置的 path 地址'});
//第三种:使用 name 关键字
this.$router.push({name : '命名路由的 name 值'});
注意:
/
this
不能省略可以发现,声明式是等价于 router.push(…)的。
任务1:使用编程式导航改造上面的代码
当我们把引用河北的
改为的时候,就发现没办法使用to引用路由了。
<!-- <router-link :to="{name:'hb'}">河北</router-link> -->
<!-- 使用按钮进行路由引用 to就没办法进行路由引用了 -->
<button>河北</button>
这时候我们给按钮添加个点击方法,并在组件中添加methods方法,代码如下:
河南 |
到此为止,可以测试是否成功。(我的都成功了)
在 Vue 路由中,针对不同的路由导航方式有不同的传参方式。这里主要是根据 path 属性或 name 属性进行区 分,无论是上面讲的声明式还是编程式操作基本一致。
用于传参的键可以为两个名词
第一种:path+query属性
提示文字
组件中获取方式
{{this.$route.query.参数名}}
第二种:name+params属性
提示文字
组件中获取方式
{{this.$route.params.参数名}}
注意
这里的 this 可以省略
这里是 r o u t e 不 是 route 不是 route不是router
任务1:在河北和河南城市中新添加li
内容为调用路由时的参数
使用第一种方式query
添加HeNanComponent.vue
中的li
标签
- 郑州
- 洛阳
- 安阳
- 商丘
- 周口
- 信阳
- {{this.$route.query.henan}}
使用第二种方式params
添加HeBeiComponent.vue
中的li
标签
- 石家庄
- 秦皇岛
- 邯郸
- 邢台
- 保定
- 张家口
- {{this.$route.params.hebei}}
添加ChengShiConponent.vue
组件中,调用路由的参数
河南 |
河北
li
标签中了。编程式导航传参和声明式导航传参差不多,只不过不是用标签,而是在方法内传参。
代码步骤如下:
因为上面修改过子路由组件内获取参数了,所以我们只修改ChengShiComponent.vue
组件就可以了。
河南 |
修改完毕后可以测试是否成功,我这里是成功了,和声明式导航传参的结果一样。
本章主要学习 Vue 路由的基本使用。其中 Vue 路由主要分为两种:
对于路由的基本操作包含有:
虽然两种不同的路由方式写法不同,但是基本操作大致一样。大家可以根据自身情况选择合适的操作。