Vue
特点
渐进式 JavaScript 框架
遵循MVVM模式
编码简洁,体积小,运行效率高
它本身只关注UI,可以轻松引入vue插件或其他第三方开发项目
下载vue.js
在官网下载
下载完引入即可
引入vue.js
//开发版本:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
//生产版本:
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
vue插件
浏览器插件
Vue.js.devtools
vscode插件
Vetur
Vue 3 Snippets
mvvm模式
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑
M:模型(Model):对应data中的数据
V:视图(View):模板代码
VM:视图模型(ViewModel)Vue实例对象
data中所有的属性,最后都出现在了vm身上
vm身上的所有属性及Vue原型上所以属性,在Vue模板中都可以直接使用
vue注意
所有被Vue所调用的函数,都不要写成箭头函数,写成普通函数,这样this才指向的是vm或者实例对象,例如watch中的函数,computed中的函数
所有不是被Vue所调用的函数,都要写成箭头函数,例如定时器,ajax回调,这个图this才指向的是vm或者组件实例对象
第一个vue程序
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
message:"hello vue"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
1.vue实例(对象)中el属性: 代表Vue的作用范围 日后在Vue的作用范围内都可以使用Vue的语法
2.vue实例(对象)中data属性: 用来给Vue实例绑定一些相关数据, 绑定的数据可以通过{{变量名}}在Vue作用范围内取出
3.在使用{{}}进行获取data中数据时,可以在{{}}中书写表达式,运算符,调用相关方法,以及逻辑运算等
4.el属性中可以书写任意的CSS选择器[jquery选择器],但是在使用Vue开发是推荐使用 id选择器 注意: el属性值不能指定body或html标签
el的另一种写法
<script>
var app=new Vue({
//model:数据
data:{
message:"hello vue"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
app.$mount('#app')
</script>
data的另一种写法
data是一个函数,返回数据对象(组件中用的多,怕重名)
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:function(){
return{
message:"hello vue"
}
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
特别注意:data不要写成箭头()=>函数,要写成普通函数,否者this的指向就是window了还不是vue实例
vue指令
指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。它们会在渲染的 DOM 上应用特殊的响应式行为
v-if
v-if
: 用来控制页面元素是否展示
写法
v-if="表达式"
v-else-if="表达式"
v-else="表达式"
适用于:切换频率比较低的场景
特点:不展示的DOM元素直接被移除
注意:v-if可以和v-else-if,v-else一起使用,但要求结构不能被打断
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-if="type==='A'">A</div>
<div v-else-if="type==='B'">B</div>
<div v-else="type==='C'">C</div>
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
type:'A'
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
v-for
v-for 指令可以绑定数组的数据来渲染一个项目列表
v-for指令:
1.用于展示列表数据
2.语法:v-for="(item, index) in arr" :key=“item.id”
3.可遍历:数组、对象、字符串
注意无论遍历什么都是是值在前面,下标在后面,最好加上:key=“唯一标识”
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-for="name in names">
{{name}}
</div>
<hr>
<div v-for="(name,index) in names">
{{index}} : {{name}}
</div>
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
names:[
'dyk','cb','lfw'
]
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
<body>
<!--
v-for指令:
1.用于展示列表数据
2.语法:v-for="(item, index) in arr" :key="item.id"
3.可遍历:数组、对象、字符串
-->
<!-- 准备好一个容器-->
<div id="root">
<h2>遍历数组</h2>
<ul>
<!-- 使用v-for遍历数组 -->
<li v-for="(stu,index) in stus" :key="stu.id">
{{stu.name}}--{{stu.sex}}--{{stu.age}}岁
</li>
</ul>
<h2>遍历对象</h2>
<ul>
<!-- 使用v-for遍历对象 -->
<li v-for="(value,key) in car" :key="key">{{value}}</li>
</ul>
<h2>遍历字符串</h2>
<ul>
<!-- 使用v-for遍历字符串 -->
<li v-for="(data,index) in str" :key="index">{{data}}--{{index}}</li>
</ul>
</div>
<script type="text/javascript" >
new Vue({
el:'#root',
data:{
stus:[
{id:'001',name:'dyk',age:20,sex:'男'},
{id:'002',name:'cb',age:19,sex:'女'},
{id:'003',name:'lfw',age:18,sex:'男'},
],
car:{
name:'奔驰c63',
price:'60万',
color:'灰色'
},
str:'abcde',
}
})
</script>
</body>
.在使用v-for的时候一定要注意加入:key 用来给vue内部提供重用和排序的唯一key
Vue中key的作用
-
虚拟DOM的key的作用
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据,生成新的虚拟dom,随后Vue进行新虚拟DOM和旧虚拟DOM的差异对比,比较规则如下 -
比较规则
旧虚拟DOM中找到了与新虚拟DOM相同的key
(1)若虚拟DOM中的内容没有变,则直接使用之前的真实DOM
(2)若虚拟DOM中的内容变了,则新生成的真实DOM,随后替换掉页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面 -
用index作为key可能引发的问题
(1)若对数据进行:逆序添加,逆序删除等破坏顺序的行为
会产生没有必要的真实DOM更新==》界面没问题,效率低
(2)如果解构中还包含输入类的DOM:
会产生错误的DOM更新 =》界面有问题 -
最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号
如果不存在对数据逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表用于展示使用index作为key是没有问题的
列表过滤
<!--
想要对数据加工后再展示,且不想破坏原数据,最好用计算属性。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<input v-model="keyWord" type="text" placeholder="请输入姓名">
<ul>
<li v-for="(p,index) in fmtPersons" :key="p.id">
{{p.name}}--{{p.sex}}--{{p.age}}岁
</li>
</ul>
</div>
<script type="text/javascript" >
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:35,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:41,sex:'男'},
{id:'004',name:'温兆伦',age:25,sex:'男'},
]
},
//使用computed过滤,优势:不影响原数据
// computed:{
// fmtPersons(){
// const {persons,keyWord} = this
// return persons.filter( p => p.name.indexOf(keyWord) !== -1)
// }
// }
computed:{
fmtPersons(){
return this.persons.filter( p => p.name.indexOf(this.keyWord) !== -1)
}
}
//在watch修改原数据,会导致原数据的丢失
/* watch:{
keyWord(value){
const arr = this.persons.filter( p => p.name.indexOf(value) !== -1)
this.persons = arr
}
} */
})
</script>
列表排序
<!--
想要对数据加工后再展示,且不想破坏原数据,最好用计算属性。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<input v-model="keyWord" type="text" placeholder="请输入姓名">
<button @click="sortType = 1">年龄升序↓</button>
<button @click="sortType = 2">年龄降序↓</button>
<button @click="sortType = 0">原顺序</button>
<ul>
<li v-for="(p,index) in fmtPersons" :key="p.id">
{{p.name}}--{{p.sex}}--{{p.age}}岁
</li>
</ul>
</div>
<script type="text/javascript" >
new Vue({
el:'#root',
data:{
keyWord:'',
sortType:0, //0原顺序 1升序 2降序
persons:[
{id:'001',name:'马冬梅',age:35,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:41,sex:'男'},
{id:'004',name:'温兆伦',age:25,sex:'男'},
]
},
//使用computed过滤,优势:不影响原数据
computed:{
fmtPersons(){
const {persons,keyWord,sortType} = this
//根据关键词过滤
let arr = persons.filter( p => p.name.indexOf(keyWord) !== -1)
//若需要排序
if(sortType){
//排序
arr.sort((a,b)=>{
if(sortType === 1) return a.age - b.age
else return b.age - a.age
})
}
return arr
}
}
})
</script>
v-bind
v-bind
: 用来绑定标签的属性从而通过vue动态修改标签的属性
注意v-bind是单向绑定
数据只能从data流向页面
就是只有改变model,view才会改变,而改变view,model不会改变
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<span v-bind:title="message"> <!-- 绑定标签用v-bind,非标签则{{xxx}} -->
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
<input type="text" v-bind:value="message">
<!-- 注意v-bind是单向绑定 -->
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
message:"hello vue"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
打开浏览器的 JavaScript 控制台,输入 app.message = ‘hahaha’,就会再一次看到这个绑定了 title attribute 的 HTML 已经进行了更新
v-bind 缩写
vue为了方便我们日后绑定标签的属性提供了对属性绑定的简化写法如 v-bind:属性名
简化之后 :属性名
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-model
它能实现view和model之间的双向绑定。
数据不仅能从data流向页面,还能从页面流向data
默认是value值即 v-model:value="" 可简写为v-model=""
v-model只能应用在表单类元素(输入类元素)上
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
<input type="text" v-model="message">
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
message:"hello vue"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
1.使用v-model指令可以实现数据的双向绑定
2.所谓双向绑定 表单中数据变化导致vue实例data数据变化 vue实例中data数据的变化导致表单中数据变化 称之为双向绑定
.lazy
焦点变更即更新
<div id="app">
{{message}}
<input type="text" v-model.lazy="message">
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
message:"hello vue"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
鼠标没点,没失去焦点之前
鼠标点了失去焦点之后
.number
只留数字,输入字符串转化为有效数字
.trim
去掉首尾空格
v-model收集数据表单
<body>
<div id="app">
<!-- 阻止表单的默认行为 -->
<form @submit.prevent="test">
账号: <input type="text" v-model="username"> <br>
密码:<input type="text" v-model="password"><br>
性别: 男<input type="radio" name="sex" v-model="sex" value="male">
女<input type="radio" name="sex" v-model="sex" value="female"> <br>
年龄:<input type="number" v-model.number="age"> <br>
爱好: 学习<input type="checkbox" name="hobby" v-model="hobby" value="study">
打游戏<input type="checkbox" name="hobby" v-model="hobby" value="game">
吃饭<input type="checkbox" name="hobby" v-model="hobby" value="eat"> <br>
城市:<select v-model="city">
<option>请选择</option>
<option value="beijing">北京</option>
<option value="shangahi">上海</option>
<option value="wuhan">武汉</option>
</select> <br>
其他信息:<textarea v-model="other"></textarea><br>
<input type="checkbox" v-model="agree">阅读接受<a href="javascript:;">《用户协议》</a><br>
<button>提交</button>
</form>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
username:'',
password:'',
sex:'',
age:'',
hobby:[],
city:'',
other:'',
agree:''
},
methods: {
test(){
console.log(JSON.stringify(this._data))
}
},
})
</script>
</body>
- 若<input type=“text” > ,则v-model收集的是value值,用户输入的就是value值
- 若<input type=“radio” > ,则v-model收集的是value值,且要给标签配置value值
- <input type=“checkbox” >
1.若没有input的value属性,那么收集的就是checked(勾选或者未勾选,布尔值) 2.配置input属性:
(1).v-model的初始值是非数组,那么收集的就是checked(勾选或未勾选,是布尔值)
(2).v-model的值是数组,那么收集到的就是value组成的数组
备注:v-model的三个修饰符
lazy:失去焦点再收集数据
number:输入字符串转为有效数字
trim:输入首位空格过滤
v-on
事件绑定,v-on指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法
事件的基本使用
1.使用v-on:xx或@xx绑定事件,其中xxx是事件名:
2.事件的回调需要配置在methods对象中,最终会在vm上
3.methods中配置的函数,不要用箭头函数,否则this就不是vm了
4.methods中的函数,都是被Vue所管理的函数,this指向vm或者组件的示例对象
5.@click=“demo”和@click="demo($event)"效果一致,但后者可以传参数
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p> {{message}}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
<script>
var app = new Vue({
el: '#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data: {
message: "hello vue"
},
//如果没有mvvm,后端给数据,前端message是不会变化
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
注意在 reverseMessage 方法中,我们更新了应用的状态,但没有触碰 DOM——所有的 DOM 操作都由 Vue 来处理,你编写的代码只需要关注逻辑层面即可
总结:
事件 事件源:发生事件dom元素 事件: 发生特定的动作 click.... 监听器 发生特定动作之后的事件处理程序 通常是js中函数
1.在vue中绑定事件是通过v-on指令来完成的 v-on:事件名 如 v-on:click
2.在v-on:事件名的赋值语句中是当前事件触发调用的函数名
3.在vue中事件的函数统一定义在Vue实例的methods属性中
4.在vue定义的事件中this指的就是当前的Vue实例,日后可以在事件中通过使用this获取Vue实例中相关数据 调用methods中相关方法
v-on缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
要传递参数又要传递事件
$event
<a @click="doSomething($event,arg0,arg1)">...</a>
Vue事件函数两种写法
<div id="app">
<span>{{count}}</span>
<input type="button" value="改变count的值" @click="changecount">
</div>
<!--引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
count:1,
},
methods:{
/*changecount:function(){
this.count++;
}*/
changecount(){
this.count++;
}
}
});
</script>
在Vue中事件定义存在两种写法
一种是 函数名:function(){}
一种是 函数名(){} 推荐
事件修饰符
1.prenent 阻止默认事件
2.stop阻止冒泡
3.once事件触发一次
4. self 用来针对于当前标签的事件触发,不监听事件冒泡
5. once 就是让指定事件只触发一次
阻止默认行为
绑定事件阻止默认行为,prevent叫事件修饰符
<body>
<div id="app">
<a href="https://www.baidu.com" @click.prevent="tobaidu">点我跳转百度</a>
</div>
<script>
var app = new Vue({
el: '#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//如果没有mvvm,后端给数据,前端message是不会变化
methods: {
tobaidu(){
alert("百度")
}
}
})
</script>
</body>
</html>
阻止冒泡
<body>
<div id="app">
<div @click="show">
<button @click.stop="tobaidu">点我</button>
</div>
</div>
<script>
var app = new Vue({
el: '#app', //el是元素element的简写,'#app'是id选择器方式绑定message
methods: {
tobaidu(){
alert("百度")
},
show(){
alert("你好")
}
}
})
</script>
</body>
</html>
如果不加stop,会弹出百度后弹出你好,加了后就只会弹百度
支持连写同时阻止冒泡,阻止默认行为
没有顺序
<body>
<div id="app">
<div @click="show">
<a href="https://www.baidu.com" @click.prevent.stop="tobaidu">点我跳转百度</a>
</div>
</div>
<script>
var app = new Vue({
el: '#app', //el是元素element的简写,'#app'是id选择器方式绑定message
methods: {
tobaidu(){
alert("百度")
},
show(){
alert("你好")
}
}
})
</script>
</body>
</html>
键盘事件
常用的:enter,esc,还可以直接写按键编码
# 按键修饰符
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
<body>
<div id="app">
<!-- 键盘事件 -->
<input type="text" @keyup.enter="show" placeholder="按下回车弹出">
</div>
<script>
var app = new Vue({
el: '#app', //el是元素element的简写,'#app'是id选择器方式绑定message
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
},
tobaidu(){
alert("百度")
},
show(){
alert("你好")
}
}
})
</script>
</body>
</html>
v-text
v-text
:用来获取data中数据将数据以文本的形式渲染到指定标签内部 类似于javascript 中 innerText
作用:向其所在的节点中渲染文本内容
与插值语法的区别:v-text取值会将标签中原有的数据覆盖,{{xx}}插值语法不会
<body>
<div id="app">
<div >你好,{{message}}</div>
<div v-text="message">你好</div>
<div v-text="message1">你好</div>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
message:"hello vue",
message1:"<h1>hello vue</h1>",
}
})
</script>
</body>
总结
{{}}(插值表达式)和v-text获取数据的区别在于
1 .使用v-text取值会将标签中原有的数据覆盖 使用插值表达式的形式不会覆盖标签原有的数据
2 .使用v-text可以避免在网络环境较差的情况下出现插值闪烁
v-html
v-html
:用来获取data中数据将数据中含有的html标签先解析在渲染到指定标签的内部 类似于javascript中 innerHTML
作用:向指定节点中渲染包含html结构的内容
与插值语法的区别:
(1).v-html会替换节点中所有的内容,{{xx}}则不会
(2).v-html会识别html结构
注意:v-html有安全性问题
在任意网站上渲染html是非常危险的,容易导致xss攻击
一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
<div v-html='url'></div>
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
message:"hello vue",
url:"<h1>www.baidu.com</h1>"
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
v-show
v-show
:用来控制页面中某个标签元素是否展示
写法:
v-show="表达式"
适用于:切换频率较高的场景
特点:不展示的DOM未被移除,仅仅只是样式隐藏掉
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-show="isshow">显示出来</div>
<div v-show="notshow">隐藏起来</div>
<button v-on:click="change">反转</button>
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
isshow:true,
notshow:false
},
//如果没有mvvm,后端给数据,前端message是不会变化
methods:{
change:function(){
this.isshow=!this.isshow;
this.notshow=!this.notshow;
}
}
})
</script>
</body>
</html>
首先只有值为true的才能显示出来,false的就不显示
点击反转后
1.在使用v-show时可以直接书写boolean值控制元素展示,也可以通过变量控制标签展示和隐藏
2.在v-show中可以通过boolean表达式控制标签的展示和隐藏
v-show和v-if的区别
v-if:
适用于:切换频率很低的场景
特点: 不展示DOM节点直接被删除
v-show:
适用于:切换频率很高的场景
特点:不展示的dom节点没有被删除,仅仅是使用样式隐藏(display:hidden)
注意:v-if使用时 dom节点可能无法获取到,而使用v-show一定可以获取到dom节点
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-show="isshow">显示出来1</div>
<div v-if="isshow">显示出来2</div>
<div v-show="notshow">隐藏起来</div>
<button v-on:click="change">反转</button>
</div>
<script>
var app=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
isshow:true,
notshow:false
},
//如果没有mvvm,后端给数据,前端message是不会变化
methods:{
change:function(){
this.isshow=!this.isshow;
this.notshow=!this.notshow;
}
}
})
</script>
</body>
</html>
v-show如果为false在原码中还能看到就是加了一个display=none,而v-if就直接看不到了
v-cloak
v-cloak指令(没有值):
1.本质是一个特殊的属性,Vue实例创建完毕后接管容器,会删掉v-ckoak属性
2.使用css配合v-cloak可以解决网速慢页面展示出来{{xx}}的问题
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
/* 属性选择器 */
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>{{message}}</h2>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
message:"hello vue"
}
})
</script>
</body>
</html>
v-once
v-once指令:
v-once所在的节点在初次动态渲染后,就视为静态内容了
以后数据的改变不会引起v-once所在的结构的更新,可以用于优化性能
<body>
<div id="app">
<h2 v-once>n初始值为:{{n}}</h2>
<h2>n当前值为{{n}}</h2>
<button @click="n++">点我加1</button>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
n:1
}
})
</script>
</body>
v-pre
v-pre指令
1.跳过其所在节点的编译过程
2.可利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
<body>
<div id="app">
<h2 v-pre>vue v-pre</h2>
<h2 v-pre>n当前值为{{n}}</h2>
<button c-pre @click="n++">点我加1</button>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
n:1
}
})
</script>
</body>
自定义指令
局部指令
new Vue({directives:{指令名:配置对象})或者 new Vue(directives:{回调函数})
<body>
<!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定值放大
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 -->
<div id="app">
<h2>当前n值是:{{n}}</h2>
<h2>放大10倍n值是:<span v-big="n"></span></h2>
<button @click="n++">点击加1</button><br>
<input type="text" v-fbind:value="n">
</div>
<script>
var app=new Vue({
el:'#app',
data:{
n:1
},
directives:{
// big函数何时被调用:
// 1.指令与元素成功绑定(一上来)
// 2.指令所在的模板被重新解析时
big(element,binding){
element.innerText=binding.value*10
},
fbind:{
//指令与元素绑定成功时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在模板被重新解析时
update(element,binding){
element.value=binding.value
}
}
}
})
</script>
</body>
全局指令
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
<body>
<!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定值放大
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 -->
<div id="app">
<h2>当前n值是:{{n}}</h2>
<h2>放大10倍n值是:<span v-big="n"></span></h2>
<button @click="n++">点击加1</button><br>
<input type="text" v-fbind:value="n">
</div>
<script>
// 定义成全局的指令
Vue.directive('big',function(element,binding){
element.innerText=binding.value*10
})
Vue.directive('fbind',{
//指令与元素绑定成功时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在模板被重新解析时
update(element,binding){
element.value=binding.value
}
})
var app=new Vue({
el:'#app',
data:{
n:1
},
})
</script>
</body>
配置对象中常用的3个回调
bind
bind:指令与元素绑定成功时(一上来) 调用
inserted
inserted:指令所在元素被插入页面时调用
update
update:指令所在模板被重新解析时调用
注意
1.指令定义时不加v-使用时加v-
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase
计算属性
计算属性:要显示的数据不存在,通过计算得来
原理:底层借助了object.defineproperty方法的getter和setter
执行时机:
初始显示会执行一次,得到初始值去显示
当依赖数据发生变化时会被再次调用
优势:与methods实现相比,内部有缓存机制,效率更高
备注:计算属性是直接用于读取使用的,不要加()
计算属性最终会出现在vm上,直接读取即可
如果计算属性要被修改,那么必须写set函数去影响改变,且set中要引起计算时依赖数据发生改变
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>ctime1:{{ctime1()}}</div>
<div>ctime2:{{ctime2}}</div>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
message:"hello vue"
},
methods:{
ctime1:function()
{
return Date.now();
}
},
computed:
{
//vue特有,计算属性,计算结果保存在内存中,重复调用不变,类似缓存
//使用时,调用属性,而非方法
ctime2:function(){
return Date.now();
}
}
})
</script>
</body>
</html>
说明计算属性是属性和方法有区别
只在相关响应式依赖发生改变时它们才会重新求值,这就意味着只要 依赖的值 还没有发生改变,多次访问 计算属性会立即返回之前的计算结果,而不必再次执行函数
计算属性底层调用Object.defineProperty
不使用框架进行编码时,什么时候用defineProperties
要追加的属性来自其他值的加工
<script >
let person={
firstName:'张',
lastNamee:'三',
}
Object.defineProperty(person,'fullName',{
enumerable:true,//控制属性是否可以被枚举,默认是false
writable:true,//控制属性是否可以被修改,默认是false
configurable:true, //控制属性是否可以被删除,默认是false
set(value){
//fullName被修改时,set被调用,且set方法中this是person,且set会收到修改的值
const arr=value.split('-')
this.firstName=arr[0]
this.lastName=arr[1]
},
get(){
//fullName被读取时,get被调用,且get方法中this是p
return this.firstName+'-'+this.lastName
}
})
</script>
简写
fullName是Vue在调用
fullName初次渲染会调用,当依赖的属性值发生变化会调用
<div id="app">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
<span>全名:{{fullName}}</span>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
firstName:'张',
lastName:'三',
},
computed:{
//简写相当于只指定了get,没有指定set
fullName(){
return this.firstName+'-'+this.lastName
}
}
})
</script>
完整写法
fullName函数底层用到的对象是setter和getter方法
<div id="app">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
<span>全名:{{fullName}}</span>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
firstName:'张',
lastName:'三',
},
computed:{
fullName:{
set(value)//fullName被修改时set被调用,set中的this是app,set会收到修改的值
{
const arr=value.split('-')
this.firstName=arr[0]
this.lastName=arr[1]
},
get() //fullName被读取时get被调用,get中的this是app
{
return this.firstName+'-'+this.lastName
}
}
}
})
</script>
侦听属性
监听属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.属性必须存在,才能进行监视,可以是属性或者计算属性
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
<div id="app">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
<span>全名:{{fullName}}</span>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
firstName:'张',
lastName:'三',
fullName:''
},
watch:{
// 函数写法函数名字应该取和data中被监听的一样
//被调用时间data中的firstName被改变时调用
//watch中发firstName中的this是vm
firstName(newvalue,oldvalue){
// console.log('firstName改变了',newvalue,oldvalue)
this.fullName=newvalue+this.lastName
},
lastName(newvalue,oldvalue){
// console.log('firstName改变了',newvalue,oldvalue)
this.fullName=this.firstName+newvalue
}
}
})
</script>
另一种写法
<div id="app">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
<span>全名:{{fullName}}</span>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
firstName:'张',
lastName:'三',
fullName:''
},
// 完整写法
watch:{
firstName:{
immediate:true,//若immediate为true则handler在初始化时就会被调用一次,以后就看firstname改变
// 方法名必须是handler
handler(newvalue,oldvalue){
this.fullName=newvalue+this.lastName
}
}
}
})
</script>
深度监视
Vue中的watch默认不监测对象内部值的改变(一层)
配置deep:true可以检测对象内部值改变(多层)
Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
使用watch时根据数据的具体结构,决定是否采用深度监视
当没开启深度监视时
<body>
<div id="app">
a的值:{{numbers.a}}<br>
<button @click="numbers.a++">按住加1</button>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
numbers:{
a:1,
b:1
}
},
// 完整写法
watch:{
//监视多级结构中某个属性变化,注意要加单引号
'numbers.a':{
handler(){
console.log('a改变了')
}
}
}
})
</script>
</body>
</html>
这样写用单引号选择对象里面的属性可以直接监视
如果要直接监视对象
<body>
<div id="app">
a的值:{{numbers.a}}<br>
<button @click="numbers.a++">按住加1</button>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
numbers:{
a:1,
b:1
}
},
//监视多级结构中所有属性变化
watch:{
numbers:{
handler()
{
console.log("numbers改变了");
}
}
}
})
</script>
</body>
发现怎么点击都不会有反应
当加上deep=true
<body>
<div id="app">
a的值:{{numbers.a}}<br>
<button @click="numbers.a++">按住加1</button>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
numbers:{
a:1,
b:1
}
},
//监视多级结构中所有属性变化
watch:{
numbers:{
deep:true,
handler()
{
console.log("numbers改变了");
}
}
}
})
</script>
conputed和watch之间的区别
1.只要是computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成,watch可以进行异步,但是hanlder里面定时器的回调一定要写成箭头函数
绑定样式
绑定class样式:
1.写法 :class=“xxx”,xxx可以是字符串,对象数组
2.字符串写法适用于:类名不确定,要动态获取
3.对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
4.数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
绑定style样式:
1.:style=“fontSize:xxx” xxx是动态值
2.:style="[a,b]" 其中a,b是样式对象
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
h2{
border: 2px solid black;
padding: 5px;
}
.classA{
color: red;
}
.classB{
background-color: bisque;
}
.classC{
height: 50px;
}
</style>
</head>
<body>
<div id="app">
<!-- 绑定class的字符串写法,适用于:类名不确定,要动态获取 -->
<h2 :class="mystyle">{{title}}</h2>
<!-- 绑定class样式的数组写法,适用于:要绑定的样式个数不确定,名字也不确定 -->
<h2 :class="classarry">{{title}}</h2>
<h2 :class="[a,b,c]">{{title}}</h2>
<!-- class的对象写法,适用于:类名确定,个数确定,但不确定用不用 -->
<h2 :class="classobj">{{title}}</h2>
<h2 :class="{classB:hasB,classC:hasC}">{{title}}</h2>
<!-- class的三元表达式写法,适用于:类名确定,但不确定用不用 -->
<h2 :class="hasB ? 'classB': ''"> {{title}}</h2>
<!-- 绑定style -->
<h2 :style="{fontSize:size+'px'}">{{title}}</h2>
<h2 :style="styleobj">{{title}}</h2>
</div>
<script>
var vm=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
title:'dyk666',
mystyle:"classA",
classarry:['classA','classB','classC'],
classobj:{
classA:true,
classB:true,
classC:true
},
hasB:true,//标识是否使用classB样式
hasC:true,//标识是否使用classC样式
a:'classA',
b:'classB',
c:'classC',
size:40,
styleobj:{
fontSize:'40px',
color:'blue',
backgroundColor:'orange',
}
}
})
</script>
</body>
</html>
绑定样式
绑定class样式
:class="xxx" xxx可以是字符串,对象,数组
绑定style样式
样式名是小驼峰
:style="{样式名:xx}"
可以传给 v-bind:class 一个对象,以动态地切换 class:
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.active{
background-color: red;
height: 100px;
}
.active2{
color: green;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{ active: isActive ,'active2': isActive2}" >dyk</div>
<button @click="change">点我</button>
</div>
<script>
var app=new Vue({
el:'#app',
//model:数据
data:{
isActive :true,
isActive2:true
},
methods:{
change:function(){
this.isActive=!this.isActive;
}
}
})
</script>
</body>
</html>
<div v-bind:class="{ active: isActive ,'active2': isActive2}" >dyk</div>
active是类的名字,active 这个 class 存在与否将取决于数据 property isActive 是true还是false,这个类加不加引号都是可以的
当 isActive 或者 isActive2 变化时,class 列表将相应地更新
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.classA{
color: red;
}
.classB{
background-color: green;
}
.classC{
color: blueviolet;
}
</style>
</head>
<body>
<div id="app">
<!-- class的字符串写法,适用于:类名不确定,要动态获取 -->
<h2 :class="mystyle">{{title}}</h2>
<!-- class的对象写法,使用于:类名确定,但不确定用不用 -->
<h2 :class="{classB:hasB,classC:hasC}">{{title}}</h2>
<!-- class的三元表达式写法,适用于:类名确定,但不确定用不用 -->
<h2 :class="hasB ? 'classB': ''"> {{title}}</h2>
<!-- class的数组写法,适用于:同时应用多个class -->
<h2 :class=[a,b,c]>{{title}}</h2>
<!-- 绑定style -->
<h2 :style="{fontSize:size+'px'}">{{title}}</h2>
</div>
<script>
var vm=new Vue({
el:'#app', //el是元素element的简写,'#app'是id选择器方式绑定message
//model:数据
data:{
title:'dyk666',
mystyle:"classA",
hasB:true,//标识是否使用classB样式
hasC:true,//标识是否使用classC样式
a:'classA',
b:'classB',
c:'classC',
size:40
}
//如果没有mvvm,后端给数据,前端message是不会变化
})
</script>
</body>
</html>
组件
组件作用:
用来减少Vue实例对象中代码量,日后在使用Vue开发过程中,可以根据 不同业务功能将页面中划分不同的多个组件,然后由多个组件去完成整个页面的布局,便于日后使用Vue进行开发时页面管理,方便开发人员维护
组件命名
- 一个单词组成:
第一种写法(首字母小写) school
第二种写法 (首字母大写)School - 多个单词组成
第一种写法 (kebab-case命名):my-school
第二种写法 (CamelCase命名):MySchool (需要Vue脚手架)
备注:组件名尽可能回避HTML已有的元素名称,例如:h2 H2都不行,可以使用name配置项指定组件在开发工具呈现的名字
组件标签
第一种写法 :
<school></school>
第二种写法:
<school/>
注意不使用脚手架时,< school/>会导致后续组件不能渲染
组件使用的三大步骤
1.定义组件(创建组件)
2.注册组件
3.使用组件(写组件标签)
定义组件
使用Vue.extend(option)创建,其中options和new Vue(options)传入的那个options几乎一样
区别如下:
- el不要写,最终所有的组件都要经过一个叫vm的管理,由vm中的el决定服务那个容器
- data必须写成函数,避免组件复用时,数据存在索引引用
备注:template可以配置组件结构
注册组件
- 局部注册:靠new Vue的时候传入components选项
//局部组件登录模板声明
let login ={ //具体局部组件名称
template:'<div><h2>用户登录</h2></div>'
};
const app = new Vue({
el: "#app",
data: {},
methods: {},
components:{ //用来注册局部组件
login:login //注册局部组件
}
});
//局部组件使用 在Vue实例范围内
<login></login>
- 全局注册;靠Vue.component(‘组件名’,组件)
//1.开发全局组件
Vue.component('login',{
template:'<div><h1>用户登录</h1></div>'
});
//2.使用全局组件 在Vue实例范围内
<login></login>
说明:全局组件注册给Vue实例,日后可以在任意Vue实例的范围内使用该组件
- 1.Vue.component用来开发全局组件 参数1: 组件的名称 参数2: 组件配置{} template:’'用来书写组件的html代码 template中必须有且只有一个root元素
- 2.使用时需要在Vue的作用范围内根据组件名使用全局组件
- 3.如果在注册组件过程中使用 驼峰命名组件的方式 在使用组件时 必须将驼峰的所有单词小写加入-线进行使用
组件标签
<school></school>
<body>
<div id="app">
<!-- 编写组件标签 -->
<school></school>
<hr>
<student></student>
<hello></hello>
</div>
<script>
//创建组件
const school=Vue.extend(
{
template:`
<div>
<h2>学校姓名:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showname">点我弹出学校名</button>
</div>`,
data() {
return {
schoolName:'wsyu',
address:'wuhan'
}
},
methods: {
showname(){
alert(this.schoolName)
}
},
}
)
const student=Vue.extend(
{
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>`,
data() {
return {
studentName:'dyk',
age:18
}
},
}
)
const hello=Vue.extend({
template:`<div>{{msg}}</div>`,
data(){
return{
msg:"haha"
}
}
})
Vue.component('hello',hello);
var app=new Vue({
el:'#app',
components:{
//局部注册
school:school,
student:student,
}
})
</script>
</body>
简写
const school= Vue.extend(options) 可简写为: const school=options
组件嵌套
<body>
<div id="app">
<!-- 编写组件标签 -->
<school></school>
<hr>
</div>
<script>
//创建组件
const student=Vue.extend(
{
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>`,
data() {
return {
studentName:'dyk',
age:18
}
},
}
)
const school=Vue.extend(
{
template:`
<div>
<h2>学校姓名:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showname">点我弹出学校名</button>
<student></student>
</div>`,
data() {
return {
schoolName:'wsyu',
address:'wuhan'
}
},
methods: {
showname(){
alert(this.schoolName)
}
},
components:{
student:student
}
}
)
var app=new Vue({
el:'#app',
components:{
//局部注册
school:school,
}
})
</script>
</body>
标准化开发
<body>
<div id="app">
</div>
<script>
//创建组件
const student=Vue.extend(
{
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>`,
data() {
return {
studentName:'dyk',
age:18
}
},
}
)
const school=Vue.extend(
{
template:`
<div>
<h2>学校姓名:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showname">点我弹出学校名</button>
<student></student>
</div>`,
data() {
return {
schoolName:'wsyu',
address:'wuhan'
}
},
methods: {
showname(){
alert(this.schoolName)
}
},
components:{
student:student
}
}
)
const hello=Vue.extend({
template:`<h2>{{msg}}</h2>`,
data(){
return {msg:'hello'}
}
})
const App=Vue.extend({
template:
`<div>
<school></school>
<hello></hello>
</div>`,
components:{
//局部注册
school:school,
hello:hello
}
})
var vm=new Vue({
template:`<App></App>`,
el:'#app',
components:{
App:App
}
})
</script>
</body>
VueComponent:
- school组件本质是一个名为 VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
- 我们只需要写< school/>或者< /school>Vue解析会帮我们创建school组件的实例对象,即Vue帮我们执行的 new VueComponent(options)
- 特别注意:每次调用Vue.extend 返回的都是一个全新的 VueComponent
- 关于this指向
(1) 组件配置:
data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均是 VueComponent实例对象
(2)new Vue(options)
data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均是 Vue实例对象
单文件组件
建立一个shcool.vue的文件,为了方便可以下个插件Vuter 直接输入<v即可生成模板
<template>
<!-- 组件的结构 -->
</template>
<script>
// 组件交互相关的代码
</script>
<style>
/* 组件的样式 */
</style>
ref属性
- 被用来给元素或者子组件注册应用信息(id的替代者)
- 应用在html标签上获取的是真实的dom元素,应用在组件标签上是组件的实例对象
- 使用方式 :< h1 ref="xxx>< /h1>或者组件标签
- 获取:this.$refs.xxx
<template>
<div>
<h1 v-text="msg" ref="title"></h1>
<button ref="btn" @click="showDOM">点我输出上分DOM元素</button>
<Student ref="sch"></Student>
</div>
</template>
<script>
import Student from './components/Student.vue'
export default {
name:'App',
components:{
Student:Student
},
methods:{
showDOM(){
console.log(this.$refs)
console.log(this.$refs.btn)//真实DOM元素
console.log(this.$refs.title)//真实DOM元素
console.log(this.$refs.sch)//school组件的实例对象
}
}
}
</script>
<style>
</style>
配置项props
功能:让组件接收外部传过来的数据
备注:props是只读属性,Vue底层会检测你对props的修改,如果进行了修改会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
(1) 传递数据 < Student name=“dyk” sex=“男” :age=“12”>< /Student> 组件里面写属性
(2)接收数据
- 只接收数据:
props:['name','age','sex']
2.接收同时对数据类型限制
props:{
name:String,
age:Number,
sex:String
}
- 限制类型,限定必要性,指定默认值
props:{
name:{
type:String,//name是字符串类型
required:true,//name是必要的
},
age:{
type:Number,
default:28 //默认值
}
},
一般default和required不会同时出现
App.vue
<template>
<div>
<Student name="dyk" sex="男" :age="12"></Student>
</div>
</template>
<script>
import Student from './components/Student.vue'
export default {
name:'App',
components:{
Student:Student
},
}
</script>
student.vue
<template>
<div class="demo1">
<h1>{{msg}}</h1>
<h2>学生姓名:{{ name }}</h2>
<h2>学生年龄:{{ myage }}</h2>
<button @click="add">点我年龄加1</button>
<!-- vue不希望改props的值,并且props里的值不能和data里面的重复,props里面值的优先级更高 -->
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
msg:"我是学生",
myage:this.age
};
},
// props:['name','age','sex'] //简单声明接收
//接收同时对数据类型限制
// props:{
// name:String,
// age:Number,
// sex:String
// }
props:{
name:{
type:String,//name是字符串类型
required:true,//name是必要的
},
age:{
type:Number,
default:28
}
},
methods:{
add(){
this.myage++;
}
}
};
</script>
通过在组件上声明静态数据传递给组件内部
//1.声明组件模板配置对象
let login = {
template:"<div><h1>欢迎:{{ userName }} 年龄:{{ age }}</h1></div>",
props:['userName','age'] //props作用 用来接收使用组件时通过组件标签传递的数据
}
//2.注册组件
const app = new Vue({
el: "#app",
data: {},
methods: {},
components:{
login //组件注册
}
});
//3.通过组件完成数据传递
<login user-name="小陈" age="23"></login>
通过在组件上声明动态数据传递给组件内部
//1.声明组件模板对象
const login = {
template:'<div><h2>欢迎: {{ name }} 年龄:{{ age }}</h2></div>',
props:['name','age']
}
//2.注册局部组件
const app = new Vue({
el: "#app",
data: {
username:"小陈陈",
age:23
},
methods: {},
components:{
login //注册组件
}
});
//3.使用组件
<login :name="username" :age="age"></login>
//使用v-bind形式将数据绑定Vue实例中data属性,日后data属性发生变化,组件内部数据跟着变化
prop的单向数据流
单向数据流:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
组件中定义数据和事件使用
在子组件中调用传递过来的相关事件必须使用 this.$emit('函数名') 方式调用
<div id="app">
<h1>{{msg}} {{count}}</h1>
<!--使用组件
在使用组件时向组件传递事件 直接在对应组件标签上定义传递事件即可 @key=value @传递事件名="父组件中传递事件名"
-->
<login name="小陈" :msg="msg" @testParent="testParent" @bb="testHehe"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
const login = {
template:`<div><h3>用户登录---{{name}}---{{msg}}</h3> <button @click="testChild">点我去掉父组件中某个事件</button></div>`,
data(){
return {
count:19
}
},
props:['name','msg'],
methods:{
testChild(){
alert('我是子组件中定义事件');
//调用父组件中testParent事件
this.$emit('testparent');//这个方法用来调用父组件传递过来事件 参数1:调用事件名
//this.$emit('bb',this.count,'xiaochen',true);//传递零散参数
//this.$emit('bb',{count:this.count,name:"小陈",sex:true});//传递零散参数
}
}
};
const app = new Vue({
el: "#app",
data: {
msg: "组件之间事件传递",
count:0
},
methods:{
testParent(){
alert('我是父组件上事件')
},
testHehe(obj){
console.log("parent:","hehe");
console.log("parent:",obj);
console.log("parent:",obj.count);
console.log("parent:",obj.name);
console.log("parent:",obj.sex);
this.count = obj.count;
}
},
components:{ //注册局部组件
login,
}
});
</script>
//1.声明组件
const login = {
template:"<div><h1>百知教育 {{ uname }}</h1> <input type='button' value='点我' @click='change'></div>",
data(){
return {
uname:this.name
}
},
props:['name'],
methods:{
change(){
//调用vue实例中函数
this.$emit('aaa'); //调用组件传递过来的其他函数时需要使用 this.$emit('函数名调用')
}
}
}
//2.注册组件
const app = new Vue({
el: "#app",
data: {
username:"小陈"
},
methods: {
findAll(){ //一个事件函数 将这个函数传递给子组件
alert('Vue 实例中定义函数');
}
},
components:{
login,//组件的注册
}
});
//3.使用组件
<login @find="findAll"></login> //=====> 在组件内部使用 this.$emit('find')
mixin(混入)
功能:可以把多个组件共用的配置提取成一个混入的对象
局部混入
App.vue
<template>
<div>
<school></school>
<student></student>
</div>
</template>
<script>
import School from './components/School.vue'
import Student from './components/Student.vue'
export default {
name:'App',
components:{
Student,
School
},
}
</script>
mixin,js
export const mymixin={
methods: {
showname() {
alert(this.name);
},
}
}
student.Vue
<template>
<div class="demo1">
<h2>学生姓名:{{ name }}</h2>
<h2>学生年龄:{{ age }}</h2>
<button @click="showname">点我弹出学生名</button>
</div>
</template>
<script>
import { mymixin } from '../mixin'
export default {
name:'Student',
data() {
return {
name: "dyk",
age: 18,
};
},
mixins:[mymixin]
};
</script>
school.vue
<template>
<!-- 组件的结构 -->
<div class="demo">
<h2>学校姓名:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
<button @click="showname">点我弹出学校名</button>
</div>
</template>
<script>
//引入myminxin
import {mymixin} from '../mixin'
export default{
name: "School",
data() {
return {
name: "wsyu",
address: "wuhan",
};
},
mixins:[mymixin]
};
</script>
全局混入
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
import {mymixin} from './mixin'
Vue.mixin(mymixin)
new Vue({
render: h => h(App),
}).$mount('#app')
自定义插件
功能:用于增强Vue
本质
包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件的使用传递的参数
定义
plugins.js
export default{
install(Vue){
console.log("vue插件",Vue);
//全局过滤器
//全局指令
//定义混入
//给Vue原型上添加一个方法
//....
Vue.prototype.hello=()=>{alert("hello")}
}
}
使用
Vue.use()
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
//引入插件
import plugins from './plugins'
//使用插件
Vue.use(plugins)
new Vue({
render: h => h(App),
}).$mount('#app')
scoped
scoped样式
作用:让样式在局部生效,防止冲突
写法:< style scoped> < /style>
Axios
中文网站:https://www.kancloud.cn/yunye/axios/234845
安装: https://unpkg.com/axios/dist/axios.min.js
axios入门链接
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
data.json
{
"employees": [
{
"firstName": "Bill",
"lastName": "Gates"
},
{
"firstName": "George",
"lastName": "Bush"
},
{
"firstName": "Thomas",
"lastName": "Carter"
}
]
}
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
</head>
<body>
<div id="app">
{{message}}
</div>
<script>
var app=new Vue({
el:'#app',
//model:数据
data:{
message:""
},
mounted()
{
axios.get('/data.json').then(
response=>(
this.message=response.data
)
)
}
})
</script>
</body>
</html>
api
set
动态在非跟数据对象(data)添加一个响应式的数据
Vue.set( target, propertyName/index, value )
参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
返回值:设置的值。
用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = ‘hi’)
<body>
<div id="app">
学号: {{student.id}} <br>
年龄: {{student.age}} <br>
姓名: {{student.name}} <br>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
student:{
id:1,
age:18,
name:'dyk'
}
}
})
</script>
</body>
如果我想动态加一个性别属性就需要使用Vue.set
<body>
<div id="app">
<h2>学号: {{student.id}} </h2><br>
<h2>年龄: {{student.age}} </h2><br>
<h2>姓名: {{student.name}} </h2><br>
<h2 v-if="student.sex">性别: {{student.sex}} </h2><br>
<button @click="addsex">添加一个性别属性</button>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
student:{
id:1,
age:18,
name:'dyk'
}
},
methods: {
addsex(){
Vue.set(vm.student,'sex','男')
//this.$set(this.student,'sex','男')
}
},
})
</script>
</body>
注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象
换句话说就是Vue不能动态添加data里面的属性,可以添加data里面下一级对象的属性,例如student对象里面的sex属性
Vue数据检测的原理:
1.vue会检测data中所有层次的数据
2.会检测对象中的数据
通过setter实现监视,且要在new Vue时就传入要检测的数据
(1)对象中后加入的属性,Vue默认不做响应式处理
(2)如需要给后添加属性做响应式,可以使用如下api
Vue.set(target,propertyName/index,value)或
vm.$set(target,propertyName/index,value)
3.如何检测数组中的数据?
通过包裹数组更新元素的方法,本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,对页面进行更新
4.在Vue修改数组中的某个元素一定要用如下方法:
在使用这些API: push() pop() shift() unshift() splice() sort() reverse()
Vue.set()或者vm. $ set()
5.特别注意Vue.set()和vm. $ set() 不能给vm或者vm的跟数据对象添加属性值
过滤器
定义:对要显示的数据进行特定格式化再显示(不适于一些简单的逻辑的处理)
语法:
1.注册过滤器
全局过滤器 :Vue.filter(name,callback)
局部过滤器: new Vue{ filters:{}}
2.使用过滤器:{{xxx | 过滤器名}} 或者 v-bind:属性=“xxx | 过滤器名”
只有插值表达式或者v-bind能使用过滤器
备注:
过滤器也可以接收额外的参数,多个过滤器也可以串联
并没有改变原本的数据,是产生的新的对应数据
<!DOCTYPE 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>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
</head>
<body>
<div id="app">
<h2>显示格式化后的时间</h2>
<h3>计算属性实现 现在是:{{fmtTime}}</h3>
<h3>methods实现 现在是:{{getFmtTime}}</h3>
<h3>过滤器实现 现在是:{{time | timeFormater}}</h3>
<h3>过滤器实现加参数 现在是:{{time | timeFormater1('YYYY-MM-DD')}}</h3>
<h3>过滤器实现加参数多级过滤 现在是:{{time | timeFormater1('YYYY-MM-DD') |mySlice}}</h3>
</div>
<script>
//全局过滤器
Vue.filter('Myslice',function(){
return value.slice(0,4)
})
var app=new Vue({
el:'#app',
data:{
time:16215611377654
},
computed:{
fmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
},
methods: {
getFmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
},
//局部过滤器
filters:{
timeFormater(value){
//return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
},
timeFormater1(value,fmt){
//return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
return dayjs(value).format(fmt);
},
mySlice(value){
return value.slice(0,4);
}
}
})
</script>
</body>
</html>
Vue生命周期
生命周期:
- 又名:生命周期函数,生命周期钩子
- Vue在关键时刻帮我们调用的一些特殊的函数
- 生命周期函数的名字不可改变,但函数的具体内容是程序员根据需求编写的
- 声明周期函数的this指向的是vm或者实例对象
# Vue生命周期总结
- 1.初始化阶段
beforeCreate(){
//1.生命周期中第一个函数,该函数在执行时Vue实例仅仅完成了自身事件的绑定和生命周期函数的初始化工作,Vue实例中还没有 Data el methods相关属性
console.log("beforeCreate: "+this.msg);
},
created(){
//2.生命周期中第二个函数,该函数在执行时Vue实例已经初始化了data属性和methods中相关方法
console.log("created: "+this.msg);
},
beforeMount(){
//3.生命周期中第三个函数,该函数在执行时Vue将El中指定作用范围作为模板编译
console.log("beforeMount: "+document.getElementById("sp").innerText);
},
mounted(){
//4.生命周期中第四个函数,该函数在执行过程中,已经将数据渲染到界面中并且已经更新页面
console.log("Mounted: "+document.getElementById("sp").innerText);
}
- 2.运行阶段
beforeUpdate(){
//5.生命周期中第五个函数,该函数是data中数据发生变化时执行 这个事件执行时仅仅是Vue实例中data数据变化页面显示的依然是原始数据
console.log("beforeUpdate:"+this.msg);
console.log("beforeUpdate:"+document.getElementById("sp").innerText);
},
updated(){
//6.生命周期中第六个函数,该函数执行时data中数据发生变化,页面中数据也发生了变化 页面中数据已经和data中数据一致
console.log("updated:"+this.msg);
console.log("updated:"+document.getElementById("sp").innerText);
},
- 3.销毁阶段
beforeDestory(){
//7.生命周期第七个函数,该函数执行时,Vue中所有数据 methods componet 都没销毁
},
destoryed(){
//8.生命周期的第八个函数,该函数执行时,Vue实例彻底销毁
}
常用的声明周期钩子
mounted
Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
发送ajax请求启动定时器,绑定自定义时间,订阅消息
beforeDestroy
清除定时器,解绑自定义事件,取消订阅消息
关于销毁Vue实例
销毁后借助Vue开发工具看不到任何信息
销毁后自定义事件会失效,但原生DOM事件仍有效
一般不会再beforeDestroy操作数据,因为操作数据,也不会触发更新流程了
vue-cli脚手架
可以看我另一篇博客安装及基本操作Vue-cli脚手架安装+nodejs安装环境配置链接
vue-cli2脚手架项目结构
gshop
|-- build : webpack相关的配置文件夹(基本不需要修改)
|-- config: webpack相关的配置文件夹(基本不需要修改)
|-- index.js: 指定的后台服务的端口号和静态资源文件夹
|-- node_modules
|-- src : 源码文件夹
|-- main.js: 应用入口js
|-- static: 静态资源文件夹
|-- .babelrc: babel的配置文件
|-- .editorconfig: 通过编辑器的编码/格式进行一定的配置
|-- .eslintignore: eslint检查忽略的配置
|-- .eslintrc.js: eslint检查的配置
|-- .gitignore: git版本管制忽略的配置
|-- index.html: 主页面文件
|-- package.json: 应用包配置文件
|-- README.md: 应用描述说明的readme文件
vue-cli3脚手架项目结构
gshop
|-- node_modules
|-- public
|-- index.html: 主页面文件
|-- src
|-- main.js: 应用入口js
|-- babel.config.js: babel的配置文件
|-- vue.config.js: vue的配置文件,需要手动添加
|-- .gitignore: git版本管制忽略的配置
|-- package.json: 应用包配置文件
|-- README.md: 应用描述说明的readme文件
关于不同版本的vue
1.vue.js与vue.runtime.xxx.js的区别
(1) vue.js是完整版的vue 包含:核心功能+模板解析器
(2)vue.runtime.xxx.js是运行版Vue ,只包含核心功能,没有模板解析器
因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到createElement函数去指定具体的内容
路由
路由:根据请求的路径按照一定的路由规则进行请求的转发从而帮助我们实现统一请求的管理
用来在vue中实现组件之间的动态切换
使用路由
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> //vue 路由js
创建组件对象
//声明组件模板
const login = {
template:'<h1>登录</h1>'
};
const register = {
template:'<h1>注册</h1>'
};
定义路由对象的规则
//创建路由对象
const router = new VueRouter({
routes:[
{path:'/login',component:login}, //path: 路由的路径 component:路径对应的组件
{path:'/register',component:register}
]
});
将路由对象注册到vue实例
const app = new Vue({
el: "#app",
data: {
username:"dyk",
},
methods: {},
router:router //设置路由对象
});
在页面中显示路由的组件
<!--显示路由的组件-->
<router-view></router-view>
根据连接切换路由
<a href="#/login">点我登录</a>
<a href="#/register">点我注册</a>
完整版
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<a href="#/login">用户登录</a>
<a href="#/reg">用户注册</a>
<!--显示路由组件标签-->
<router-view></router-view>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
//登录组件
const login={
template:`<div><h3>用户登录</h3></div>`
};
//注册组件
const reg={
template:`<div><h3>用户注册</h3></div>`
};
//404组件
const notFound ={
template:`<div><h3>404 Not Found!,当前页面走丢了!!!!</h3></div>`
};
//1.创建路由规则对象
const router = new VueRouter({
routes:[ //配置路由规则 //redirect: 路由重定向
{path:'/',redirect:'/login'},
{path:'/login',component:login},
{path:'/reg',component:reg},
{path:'*',component:notFound},//这个路由必须要放在路由规则最后后面
]
});
const app = new Vue({
el: "#app",
data: {
msg:"vue router 基本使用"
},
methods:{},
router,//注册路由
});
</script>
router-link使用
作用:用来替换我们在切换路由时使用a标签切换路由
好处:就是可以自动给路由路径加入#不需要手动加入
<router-link to="/login" tag="button">我要登录</router-link>
<router-link to="/register" tag="button">点我注册</router-link>
总结:
1.router-link 用来替换使用a标签实现路由切换 好处是不需要书写#号直接书写路由路径
2.router-link to属性用来书写路由路径 tag属性:用来将router-link渲染成指定的标签
标签的3种切换方式
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--路径切换路由: 根据请求路径切换显示不同组件-->
<!--切换路由链接-->
<a href="#/login">用户登录</a>
<a href="#/register">用户注册</a>
<!--切换路由标签 router-link 标签必须加入 to属性 to="路由路径" -->
<router-link to="/login">用户登录</router-link>
<router-link to="/register">用户注册</router-link>
<!--切换路由标签-->
<router-link :to="{path:'/login'}">用户登录</router-link>
<router-link :to="{path:'/register'}">用户注册</router-link>
<!--名称切换路由: 根据路由对象名称切换路由显示不同组件 根据路由名称切换路由只能使用router-link 推荐使用命名路由-->
<router-link :to="{name:'Login'}">用户登录</router-link>
<router-link :to="{name:'Register'}">用户注册</router-link>
<!--展示路由组件标签-->
<router-view/>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
//login
const login = {
template:`<div><h4>用户登录</h4></div>`
};
//register
const register = {
template:`<div><h4>用户注册</h4></div>`
};
//1.创建路由规则对象
const router = new VueRouter({
routes:[
//name:这个属性代表路由对象名称 用来给路由对象一个唯一名称标识
{path:'/login',component:login,name:'Login'},
{path:'/register',component:register,name:'Register'},
]
});
const app = new Vue({
el: "#app",
data: {
msg:"vue router 基本使用之使用router-link切换路由"
},
methods:{},
router,//注册路由对象
});
</script>
js代码切换路由
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--切换路由: 1.通过标签直接切换 2.在js代码中切换-->
<router-link :to="{name:'Login'}">用户登录</router-link>
<router-link :to="{name:'Register'}">用户注册</router-link>
<!--2.在js代码中切换路由-->
<button @click="login">用户登录</button>
<button @click="register">用户注册</button>
<!--展示路由组件标签-->
<router-view/>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
//login
const login = {
template:`<div><h4>用户登录</h4></div>`
};
//register
const register = {
template:`<div><h4>用户注册</h4></div>`
};
//1.创建路由规则对象
const router = new VueRouter({
routes:[
//name:这个属性代表路由对象名称 用来给路由对象一个唯一名称标识
{path:'/login',component:login,name:'Login'},
{path:'/register',component:register,name:'Register'},
]
});
//解决同一个路由多次切换报错的问题
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
};
const app = new Vue({
el: "#app",
data: {
msg:"vue router 基本使用之在js代码中切换路由"
},
methods:{
login(){
//发送axios请求完成登录 响应回来之后切换路由到主页
//this.$route object 当前路由对象 this.$router vueRouter 代表路由管理器对象
//this.$router.push('/login');//切换路由
//this.$router.push({path:'/login'});
//在vuerouter 中多次切换相同路由出现错误 1.每次切换之前手动判断 2.加入官方一段配置解决错误问题
// if(this.$route.name!='Login'){
// this.$router.push({name:'Login'});//使用名称切换
// }
this.$router.push({name:'Login'});//使用名称切换
},
register(){
//console.log(this.$route.name);
// if(this.$route.name!='Register') {
// this.$router.push({name: 'Register'});//使用名称切换
// }
this.$router.push({name: 'Register'});//使用名称切换
}
},
router,//注册路由对象
});
</script>
解决一个路由切换多次报错
//解决同一个路由多次切换报错的问题
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
};
路由中参数传递
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--标签形式切换路由
地址栏传递参数分为两种方式:
1.queryString ? this.$route.query.key
2.restful 路径传递参数 /xx/21 this.$route.params.key
-->
<a href="#/login?name=xiaochen&password=123">用户登录</a>
<a href="#/register/21/xiaochen">用户注册</a>
<!--query-->
<router-link to="/login?name=xiaohei&password=123456">用户登录</router-link>
<router-link :to="{path:'/login',query:{name:'xiaohong',password:123456}}">用户登录</router-link>
<router-link :to="{name:'Login',query:{name:'xiaohei',password:123456}}">用户登录</router-link>
<!--restful-->
<router-link :to="{path:'/register/22/xiaojindou'}">用户注册</router-link>
<router-link :to="{name:'Register',params:{id:233,name:'xiaojinniu'}}">用户注册</router-link>
<!--展示路由组件标签-->
<router-view/>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
//login
const login = {
template:`<div><h4>用户登录</h4></div>`,
created(){ //声明周期 在执行已经组件内部事件 和 声明周期函数注册 自身 data methods computed属性注入和校验
console.log("created");
console.log(this.$route);//获取当前路由对象
console.log(this.$route.query.name);//获取当前路由对象
console.log(this.$route.query.password);//获取当前路由对象
}
};
//register
const register = {
template:`<div><h4>用户注册</h4></div>`,
created(){
console.log(this.$route);
console.log(this.$route.params.id);
console.log(this.$route.params.name);
}
};
//1.创建路由规则对象
const router = new VueRouter({
routes:[
//name:这个属性代表路由对象名称 用来给路由对象一个唯一名称标识
{path:'/login',component:login,name:'Login'},
{path:'/register/:id/:name',component:register,name:'Register'},
]
});
const app = new Vue({
el: "#app",
data: {
msg:"vue router 基本使用之参数传递"
},
methods:{},
router,//注册路由对象
});
</script>
vuex
- Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
创建vue cli中创建store文件夹
在stroe中创建index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
//1.安装vuex
Vue.use(Vuex);
//2.创建store对象
const store = new Vuex.Store({
});
//3.暴露store对象
export default store;
在main.js中引入stroe并注册到vue实例
import Vue from 'vue'
import App from './App'
import router from './router'
import store from "./stroe";//引入store
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>',
store,//注册状态
})
state属性
# 1.state属性
- 作用: 用来全局定义一些共享的数据状态
# 2.语法
const store = new Vuex.Store({
state:{
counter:0,//定义共享状态
},
}
# 3.使用
{{$store.state.counter}} ===> {{this.$store.state.counter}}
mutations 属性
# 1.mutations 属性
- 作用: 用来定义对共享的数据修改的一系列函数
# 2.语法
const store = new Vuex.Store({
state:{
counter:0,//定义共享状态
},
mutations:{
//增加
increment(state){
state.counter++
},
//减小
decrement(state){
state.counter--
}
}
});
# 3.使用
this.$store.commit('decrement');
this.$store.commit('increment');
# 4.mutations传递参数
- a.定义带有参数的函数
mutations:{
//addCount 参数1:state 对象 参数2:自定义参数
addCount(state,counter){
console.log(counter);
return state.counter += counter ;
}
}
- b.调用时传递参数
this.$store.commit('addCount',11);
mutations传递参数默认有一个参数是state,要传自己的参数只能传一个,多个自己的参数用对象传递
getters 属性
# 1.getters 属性
- 官方: 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据
它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
- 作用: 用来定义对共享的数据的计算相关的一系列函数 相当于 computed 属性 会对结果进行缓存
# 2.语法
getters:{
//平方
mathSqrts(state){
console.log("--------");
return state.counter*state.counter;
},
//乘以一个数字
mathSqrtsNumber(state,getters){
return getters.mathSqrts*3;
},
//传递参数
mathSqrtsNumbers(state,getters){
return function (number){
return number;
}
}
}
# 3.使用
- 1.{{$store.getters.mathSqrts}}
- 2.{{$store.getters.mathSqrtsNumber}}
- 3.{{$store.getters.mathSqrtsNumbers(3)}}