目录
1 声明式渲染功能
api
vue只要管控了元素,用{{}}就能得到所需要的值
<div id="app">
//数据绑定{{}} 获取那么值显示
<h1>{{name}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
//声明式渲染功能
var vm=new Vue({
//el: 管控
el:"#app",
//data里放对象
data:{
name:"张三"
},
});
</script>
页面可修改显示的值
2 常用内置指令
- v:text : 更新元素的 textContent
- v-html : 更新元素的 innerHTML
- v-if : 如果为 true, 当前标签才会输出到页面
- v-else: 如果为 false, 当前标签才会输出到页面
- v-show : 通过控制 display 样式来控制显示/隐藏
- v-for : 遍历数组/对象
- v-on : 绑定事件监听, 一般简写为@
- v-bind : 强制绑定解析表达式, 可以省略 v-bind
- v-model : 双向数据绑定
- ref : 指定唯一标识, vue 对象通过$els 属性访问这个元素对象
- v-cloak : 防止闪现, 与 css 配合: [v-cloak] { display: none }
2.1.v-on 绑定事件
v-on可以写成@
<div id="app">
<input type="text" v-model="num">
<!--v-on:click 简写为@click -->
<button v-on:click="num ++">点赞</button>
<button v-on:click="quxiao">取消点赞</button>
//数据绑定{{}} 获取那么值显示
<h1>{{name}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
//声明式渲染功能
var vm=new Vue({
//el: 管控
el:"#app", //绑定元素
//data里放对象
data:{ //封装数据
name:"张三"
},
methods: { //封装方法
quxiao(){
this.num--;
}
},
});
</script>
v-on:click.prevent="dianji"或者 @click.prevent="dianji"
修饰符:
.stop - 调用 event.stopPropagation()。阻止事件冒泡到父类
.prevent - 调用 event.preventDefault()。阻止默认事件发生
.capture - 添加事件侦听器时使用 capture 模式。 使用事件捕获模式
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
2.2 v-text 不转义
<div id="app">
<span v-text="msg"></span>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
msg:"<h1>hello</h1>"
},
})
</script>
2.3 v-html 转义
<div id="app">
<span v-html="msg"></span>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
msg:'<a href="http://www.baidu.com">百度一下</a>'
},
})
</script>
2.4 v-bind 给html绑定属性
v-bind 可以写成 :
class和style绑定,要更改为对象,class属性为true则显示
<div id="app">
<a v-bind:href="link">点击</a>
<!--class style-->
<span v-bind:class="{active:iserror}"
v-bind:style="{color: color1,'font-size': size}">ok</span>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
link:"http://www.baidu.com",
iserror:true,
color1:'red',
size:'80px'
},
})
})
</script>
2.5 v-model 双向绑定
v-model代表输入框与vue里num绑定,模型变化,引起视图变化
<div id="app">
<input type="text" v-model="num">
//数据绑定{{}} 获取那么值显示
<h1>{{name}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
//声明式渲染功能
var vm=new Vue({
//el: 管控
el:"#app",
//data里放对象
data:{
name:"张三"
},
});
</script>
<div id="app">
<input type="checkbox" v-model="language" value="java">java
<br>
<input type="checkbox" v-model="language" value="js">js
<br>
<input type="checkbox" v-model="language" value="python"> python
<br>
选中了 {{language.join(",")}}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
language:[]
},
})
</script>
2.6 v-for
<div id="demo">
<h2>测试: v-for 遍历数组</h2>
<ul>
<li v-for="(item,index) in items" :key="item.message">
{{parentMessage}}-----{{index}}----{{item.message}}
<button @click="deleteI(index)">删除</button>
<button @click="updateI(index,{message:'up'})">更新</button>
<button @click="addI(index,{message:'add'})">插入</button>
</li>
</ul>
<h2>测试: v-for 遍历对象</h2>
<ul>
<li v-for="(value,name,index) in object">
{{parentMessage}}----{{index}}---- {{name}}----{{value}}
</li>
</ul>
<h2>测试: v-for 遍历对象</h2>
<ul>
<li v-for="(value,name,index) in items[0]">
{{parentMessage}}----{{index}}---- {{name}}----{{value}}
</li>
</ul>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#demo',
data: {
parentMessage: 'Parent',
items: [{
message: 'Foo'
},
{
message: 'Bar'
}
],
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
},
methods: {
deleteI(index) {
this.items.splice(index, 1)
},
updateI(index, newi) {
this.items.splice(index, 1, newi);
},
addI(index, newi) {
this.items.splice(index, 0, newi);
}
},
})
</script>
2.6.1 数组循环
<ul>
<li v-for="(item,index) in items" :key="item.message">
{{parentMessage}}-----{{index}}----{{item.message}}
<button @click="deleteI(index)">删除</button>
<button @click="updateI(index,{message:'up'})">更新</button>
<button @click="addI(index,{message:'add'})">插入</button>
</li>
</ul>
key:来区分不同数据,提高vue渲染效率,必须是唯一值
其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名
index:下标
2.6.2 对象
<h2>测试: v-for 遍历对象</h2>
<ul>
<li v-for="(value,name,index) in object">
{{parentMessage}}----{{index}}---- {{name}}----{{value}}
</li>
</ul>
<h2>测试: v-for 遍历对象</h2>
<ul>
<li v-for="(value,name,index) in items[0]">
{{parentMessage}}----{{index}}---- {{name}}----{{value}}
</li>
</ul>
key:来区分不同数据,提高vue渲染效率,必须是唯一值
value:值
name:key
index:下标
2.6.3 显示过滤/排序后的结果
<div id="demo">
<input type="text" v-model="searchName">
<ul>
<li v-for="(p, index) in filterPersons" :key="index">
{{index}}---{{p.name}}---{{p.age}}
</li>
</ul>
<div>
<button @click="setOrderType(2)">年龄升序</button>
<button @click="setOrderType(1)">年龄降序</button>
<button @click="setOrderType(0)">原本顺序</button>
</div>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#demo',
data: {
searchName:'',
orderType:0,
persons: [{
name: 'Tom',
age: 18
},
{
name: 'Jack',
age: 17
},
{
name: 'Bob',
age: 19
},
{
name: 'Mary',
age: 16
}
]
},
computed: {
filterPersons() {
//取出相关数据
const {persons,searchName,orderType} = this
let arr;
//filter过滤数据
// arr = persons.filter(p => p.name.indexOf(searchName)!==-1)
arr=persons.filter(function(p){
return p.name.indexOf(searchName)!=-1
})
//排序
if(orderType !=0){
arr.sort(function(p1,p2){
if(orderType ==1){
return p1.age-p2.age
}
if(orderType ==2){
return p2.age-p1.age
}
})
// arr.sort((p1,p2) => p1.age-p2.age)
}
return arr;
}
},
methods: {
setOrderType(orderType){
this.orderType=orderType
}
},
})
</script>
2.7 v-if和v-else-if和v-else 条件渲染
<div id="app">
<li v-for="(user,index) in users">
<span v-for="(v,k,index) in user">{{k}}--{{v}}--{{index}};</span>
<span v-if="user.gender=='男'">是男的</span>
<span v-else-if="user.gender=='女'">是女的</span>
</li>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
users:[{name:"名字1",age:1,gender:"男"},
{name:"名字2",age:2,gender:"女"}
]
},
})
</script>
2.7.1 v-if 与 v-show的区别
<div id="demo">
<p v-if="ok">表白成功</p>
<p v-else>表白失败</p>
<hr>
<p v-show="ok">求婚成功</p>
<p v-show="!ok">求婚失败</p>
<button @click='ok=!ok'>按钮</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#demo',
data: {
ok:false
},
})
</script>
2.8 ref : 指定唯一标识, vue 对象通过$els 属性访问这个元素对象
<body>
<div id="example">
<p ref="msg">abcd</p>
<button @click="hint">提示</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#example',
data: {
},
methods: {
hint () {
alert(this.$refs.msg.innerHTML)
}
}
})
</script>
2.9 v-cloak 防止闪现
<body>
<div id="example">
<p v-clock="msg">{{msg}}</p>
<button @click="hint">提示</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
alert('---')
new Vue({
el: '#example',
data: {
msg: 'aaa'
},
methods: {
hint () {
alert(this.$refs.msg.innerHTML)
}
}
})
</script>
在第一次执行时
添加样式后防止闪现
<style>
[v-clock]{
display: none;
}
</style>
3 注册自定义指令(全局指令和局部指令)
- 注册全局指令
Vue.directive(‘my-directive’, function(el, binding){
el.innerHTML = binding.value.toupperCase()
}) - 注册局部指令
directives : {
‘my-directive’ : {
bind (el, binding) {
el.innerHTML = binding.value.toupperCase()
}
}
} - 使用指令
v-my-directive=‘xxx’
<!--
需求: 自定义2个指令
1. 功能类型于v-text, 但转换为全大写
2. 功能类型于v-text, 但转换为全小写
-->
<div id="text1">
<p v-upper-text="msg"></p>
<p v-lower-text="msg"></p>
</div>
<div id="text2">
<p v-upper-text="msg"></p>
<p v-lower-text="msg"></p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
// 注册一个全局指令
// el: 指令所在的标签对象
// binding: 包含指令相关数据的容器对象
Vue.directive('upper-text',function(el,binding){
//转大写toUpperCase()
el.textContent=binding.value.toUpperCase()
})
new Vue({
el: '#text1',
data: {
msg: 'abSSDSdsf'
},
//局部自定义指令
directives:{
'lower-text':function(el,binding){
//转小写toLowerCase()
el.textContent=binding.value.toLowerCase()
}
}
})
new Vue({
el: '#text2',
data: {
msg: 'SDAsdsS'
}
})
</script>
4 自定义插件
api
js页面编写自定义插件:
javascript中: (function(){})()是匿名函数du,主要利用函数内的变量作用域,避免产生全局变量,影响整体页面环境,增加代码的兼容性
(function(){})是一个标准的函数定义,但是没有复制给任何变量。所以是没有名字的函数,叫匿名函数。没有名字就无法像普通函数那样随时随地调用了,所以在他定义完成后就马上调用他,后面的括号()是运行这个函数的意思
(function(){
const MyPlugin = {}
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property属性
Vue.myGlobalMethod = function () {
// 逻辑...
console.log('Vue函数对象的myGlobalMethod()')
}
// 2. 添加全局资源
Vue.directive('my-directive',function(el,binding){
el.textContent=binding.value.toUpperCase()
})
// 4. 添加实例方法
<!--添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现-->
Vue.prototype.$myMethod = function () {
// 逻辑...
console.log('添加方法myMethod()')
}
}
window.MyPlugin=MyPlugin
})()
页面
<body>
<div id="test">
<p v-my-directive='msg'></p>
</div>
<!--自定义js插件要在vue下面-->
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="own.js"></script>
<script type="text/javascript">
<!--全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成-->
Vue.use(MyPlugin)
const vm = new Vue({
el: '#test',
data: {
msg: 'have'
},
})
Vue.myGlobalMethod();
vm.$myMethod();
</script>
5 计算属性(computed)和侦听器(watch)
<div id="app">
<li>西游记 价格:{{xyjprice}} 数量:<input type="number" v-model="xyjnum"></li>
<li> 水浒传 价格:{{shzprice}} 数量:<input type="number" v-model="shznum"></li>
<li> 总价格 :{{total}}</li>
{{msg}}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm= new Vue({
el:"#app",
data:{
xyjprice:99,
shzprice:88,
xyjnum:1,
shznum:1,
msg:""
},
//计算属性
computed: {
total(){
return this.xyjprice*this.xyjnum+this.shzprice*this.shznum;
}
},
//侦听器
watch: {
xyjnum(newnum,oldnum){
if(newnum>=3){
this.msg="超出限值";
this.xyjnum=3;
}
else if(newnum<=0){
this.msg="不能小于0";
this.xyjnum=0;
}
else{
this.msg="";
}
}
},
})
</script>
例:
5.1计算属性(computed) set和get用法
计算属性:
通过getter/setter实现对属性数据的显示和监听,计算属性存在缓存,多次读取只执行一次getter
6 过滤器(全局)
<div id="app">
<li v-for="user in users":key="user.name">
{{user.name}}-{{user.age}}- {{user.gender | genderFilter}}--
{{user.gender | gFilter}}
</li>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
//全局过滤器
Vue.filter("gFilter",function(val){
if(val==1){
return "男(全局)";
}
else{
return "女(全局)";
}
})
var vm = new Vue({
el: "#app",
data: {
users:[{name:"名字1",age:1,gender:1},
{name:"名字2",age:2,gender:2}
]
},
//局部过滤器
filters:{
genderFilter(val){
if(val==1){
return "男";
}
else{
return "女";
}
}
}
})
</script>
7 组件(全局和局部)
组件是可复用的 Vue 实例,在注册组件时一定要通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用
<div id="app">
<click></click>
<click></click>
<click></click>
<one-component></one-component>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
//全局
Vue.component("click",{
template : `<button v-on:click="count++">全局点击{{count}}下</button>`,
data() {
return {
count : 1
}
},
});
//局部
const oneComponent={
template : `<button v-on:click="count++">局部点击{{count}}下</button>`,
data() {
return {
count : 1
}
},
}
let vm= new Vue({
el:"#app",
data:{
},
components:{
"oneComponent":oneComponent
},
})
</script>
8 事件处理(绑定监听、事件修饰符)
<div id="example">
<h2>1. 绑定监听</h2>
<button @click="test1">test1</button>
<button @click="test2('abc')">test2</button>
<button @click="test3('abcd', $event)">test3</button>
<h2>2. 事件修饰符</h2>
<a href="http://www.baidu.com" @click.prevent="test4">百度一下</a>
<div style="width: 200px;height: 200px;background: red" @click="test5">
<div style="width: 100px;height: 100px;background: blue" @click.stop="test6"></div>
</div>
<h2>3. 按键修饰符</h2>
<input type="text" @keyup.13="test7">
<input type="text" @keyup.enter="test7">
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#example',
data: {
},
methods: {
test1(event) {
alert(event.target.innerHTML)
},
test2 (msg) {
alert(msg)
},
test3 (msg, event) {
alert(msg+'---'+event.target.textContent)
},
test4 () {
alert('点击了链接')
},
test5 () {
alert('out')
},
test6 () {
alert('inner')
},
test7 (event) {
console.log(event.keyCode)
alert(event.target.value)
}
}
})
</script>
8.1 绑定监听
v-on:xxx=“fun”
@xxx=“fun”
@xxx=“fun(参数)”
默认事件形参: event
隐含属性对象: $event
<button @click="test3('abcd', $event)">test3</button>
<script type="text/javascript">
new Vue({
el: '#example',
data: {
},
methods: {
test3 (msg, event) {
alert(msg+'---'+event.target.textContent)
},
}
})
</script>
8.2 事件修饰符
.prevent : 阻止事件的默认行为 event.preventDefault()
.stop : 停止事件冒泡 event.stopPropagation()
未添加时:
添加修饰符以后:
9 事件 $on $once $off $emit
参考 13.2.2 自定义事件 实例
- vm. o n ( e v e n t , c a l l b a c k ) 监 听 当 前 实 例 上 的 自 定 义 事 件 。 事 件 可 以 由 v m . on( event, callback ) 监听当前实例上的自定义事件。事件可以由 vm. on(event,callback)监听当前实例上的自定义事件。事件可以由vm.emit 触发。回调函数会接收所有传入事件触发函数的额外参数。
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
// => "hi"
- vm.$once( event, callback )
用法:
监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。 - vm.$off( [event, callback] )
用法:
移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
如果只提供了事件,则移除该事件所有的监听器;
如果同时提供了事件与回调,则只移除这个回调的监听器。 - vm.$emit( eventName, […args] )
触发当前实例上的事件。附加参数都会传给监听器回调。
10 vue对象的生命周期
钩子函数 | 触发的行为 | 在此阶段可以做的事情 |
---|---|---|
beforeCreate(创建前) | vue实例的挂载元素$el和数据对象data都为undefined,还未初始化 | 加loading事件 |
created(创建后) | vue实例的数据对象data有了,$el还没有 | 结束loading、请求数据为mounted渲染做准备 |
beforeMount(载入前) | vue实例的$el和data都初始化了,但还是虚拟的dom节点,具体的data.filter还未替换。 | |
mounted(载入后) | vue实例挂载完成,data.filter成功渲染 | 配合路由钩子使用 |
beforeUpdate(更新前) | data更新时触发 | 结束loading、请求数据为mounted渲染做准备 |
updated(更新后) | data更新时触发 | 数据更新时,做一些处理(此处也可以用watch进行观测) |
beforeDestroy(销毁前) | 组件销毁时触发 | |
destroyed(销毁后) | 组件销毁时触发,vue实例解除了事件监听以及和dom的绑定(无响应了),但DOM节点依旧存在 | 组件销毁时进行提示 |
vue对象的生命周期
1). 初始化显示
* beforeCreate()
* created()
* beforeMount()
* mounted()
2). 更新状态
* beforeUpdate()
* updated()
3). 销毁vue实例: vm.$destory()
* beforeDestory()
* destoryed()
2. 常用的生命周期方法
created()/mounted(): 发送ajax请求, 启动定时器等异步任务
beforeDestory(): 做收尾工作, 如: 清除定时器
11 过滤&动画
- vue动画的理解
操作css的trasition或animation
vue会给目标元素添加/移除特定的class - 基本过渡动画的编码
1). 在目标元素外包裹
2). 定义class样式
1>. 指定过渡样式: transition
2>. 指定隐藏时的样式: opacity/其它 - 过渡的类名
xxx-enter-active: 指定显示的transition
xxx-leave-active: 指定隐藏的transition
xxx-enter: 指定隐藏时的样式
<style>
/*指定过渡样式*/
.xxx-enter-active, .xxx-leave-active {
transition: opacity 1s
}
/*指定隐藏时的样式*/
.xxx-enter, .xxx-leave-to {
opacity: 0;
}
.move-enter-active {
transition: all 1s
}
.move-leave-active {
transition: all 3s
}
.move-enter, .move-leave-to {
opacity: 0;
transform: translateX(20px)
}
</style>
</head>
<body>
<div id="demo">
<button @click="show = !show">Toggle</button>
<transition name="xxx">
<p v-show="show">hello</p>
</transition>
</div>
<hr>
<div id="demo2">
<button @click="show = !show">Toggle2</button>
<transition name="move">
<p v-show="show">hello</p>
</transition>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#demo',
data: {
show: true
}
})
new Vue({
el: '#demo2',
data: {
show: true
}
})
</script>
- 在目标元素外包裹
- 定义 class 样式
指定过渡样式: transition
指定隐藏时的样式: opacity/其它
12 自定义过滤器 (自定义日期)
- 理解过滤器
功能: 对要显示的数据进行特定格式化后再显示
注意: 并没有改变原本的数据, 可是产生新的对应的数据 - 编码
1). 定义过滤器
Vue.filter(filterName, function(value[,arg1,arg2,…]){
// 进行一定的数据处理
return newValue
})
2). 使用过滤器{{myData | filterName}}{{myData | filterName(arg)}}
<body>
<div id="test">
<h2>显示格式化的日期时间</h2>
<p>{{time}}</p>
<p>最完整的: {{time | dateString}}</p>
<p>最完整的: {{time | dateString2('YYYY-MM-DD')}}</p>
<p>最完整的: {{time | dateString2('HH:mm:ss')}}</p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/moment.js/2.22.1/moment.js"></script>
<script>
Vue.filter('dateString',function(value){
return moment(value).format('YYYY-MM-DD HH:mm:ss');
})
//如果有格式,显示有的,如果没有显示默认
Vue.filter('dateString2',function(value,format='YYYY-MM-DD HH:mm:ss'){
return moment(value).format(format);
})
new Vue({
el: '#test',
data: {
time : new Date(),
},
mounted () {
setInterval(() => {
this.time = new Date()
}, 1000)
}
})
</script>
13 vue组件化编码
13.1 基本使用 components
App.vue
<template>
<div class="todo-wrap">
// 3) 使用组件标签
<todosHead/>
<todosList/>
<todosFoot/>
</div>
<template/>
<script>
//1) 引入组件
import todosHead from './components/todosHead.vue'
import todosList from './components/todosList.vue'
import todosFoot from './components/todosFoot.vue'
export default {
//2) 映射成标签
components: {
todosHead,todosList,todosFoot
}
}
<script>
13.2 组件间通信
13.2.1. props
- 此方式用于父组件向子组件传递数据
- 所有标签属性都会成为组件对象的属性, 模板页面可以直接引用
- 问题:
a. 如果需要向非子后代传递数据必须多层逐层传递
b. 兄弟组件间也不能直接 props 通信, 必须借助父组件才可以
props声明类型
实例
App.vue
<template>
<div class="todo-wrap">
<todosHead :addTodo="addTodo"/>
</div>
<template/>
<script>
import todosHead from './components/todosHead.vue'
export default {
methods: {
//给todosHead页面传方法
addTodo(todo){
//在数组中添加对象 unshift第一顺位添加
this.todos.unshift(todo)
}
},
components: {
todosHead
}
}
<script>
todosHead.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="addItem"/>
</div>
</template>
<script>
export default {
props: {
//声明addTodo为方法
addTodo: Function
},
data() {
return {
title: ''
}
},
methods: {
addItem(){
//1.检查输入的合法性
const title=this.title.trim()
if(!title){
alert("请输入")
return
}
//2.根据输入生成todo对象
const todo={
title,
complete:false
}
//3.todo对象添加todos中
this.addTodo(todo)
//4.清空
this.title=''
}
},
}
</script>
13.2.2. 自定义事件
- 此方式只用于子组件向父组件发送消息(数据)
- 问题: 隔代组件或兄弟组件间通信此种方式不合适
// 通过 v-on 绑定
@delete_todo="deleteTodo"
// 触发事件(只能在父组件中接收)
this.$emit(eventName, data) //eventName方法名,参数data(可选)
实例
App.vue
<template>
<div class="todo-wrap">
<todosHead @addTodo="addTodo"/><!--@addTodo:自定义事件名,"addTodo" 回调函数-->
</div>
<template/>
<script>
import todosHead from './components/todosHead.vue'
export default {
methods: {
//给todosHead页面传方法
addTodo(todo){
//在数组中添加对象 unshift第一顺位添加
this.todos.unshift(todo)
}
},
components: {
todosHead
}
}
<script>
todosHead.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="addItem"/>
</div>
</template>
<script>
export default {
props: {
//声明addTodo为方法
addTodo: Function
},
data() {
return {
title: ''
}
},
methods: {
addItem(){
//1.检查输入的合法性
const title=this.title.trim()
if(!title){
alert("请输入")
return
}
//2.根据输入生成todo对象
const todo={
title,
complete:false
}
//3.todo对象添加todos中
//触发addTodo自定义事件
this.$emit('addTodo',todo)
//4.清空
this.title=''
}
},
}
</script>
或者使用$refs 传递函数
app.vue
<todosHead ref="header"/>
mounted() { //执行异步代码
this.$refs.header.$on("header", this.addTodo)//指向header标签对象,$on监听名addTodo,回调函数addTodo
},
13.2.3.PubSubJS 此方式可实现任意关系组件间通信(数据)
//安装
npm install --save pubsub-js
//查询
npm info pubsub-js
//App.vue导入
import PubSub from '../node_modules/pubsub-js'
//订阅消息
PubSub.subscribe('msg', function(msg, data){})
//发布消息
PubSub.publish('msg', data)
13.2.4. 此方式用于父组件向子组件传递标签数据
slot
//子组件: Child.vue
<template>
<div>
<slot name="xxx">不确定的标签结构 1</slot>
<div>组件确定的标签结构</div>
<slot name="yyy">不确定的标签结构 2</slot>
</div>
</template>
//父组件: Parent.vue
<child>
<div slot="xxx">xxx 对应的标签结构</div>
<div slot="yyy">yyyy 对应的标签结构</div>
</child>
实例
原来,用solt组件传递只是测试,没有实现功能
App.vue
<div class="todo-wrap">
<TodosHead @addTodos='addTodos'/><!--@addTodo:自定义事件名,"addTodo" 回调函数-->
<TodosList :todos="todos"/>
<TodosFoot :todos="todos" :selectAllTodos="selectAllTodos" :deleteCompleteTodos="deleteCompleteTodos"/>
</div>
TodosFoot.vue
<div class="todo-footer">
<label>
<input type="checkbox" v-model="checkAll"/>
</label>
<span>
<span>已完成{{completeSize}}</span> / 全部{{todos.length}}
</span>
<button class="btn btn-danger" v-show="completeSize" @click="deleteAllCompleted">清除已完成任务</button>
</div>
用solt
App.vue
<div class="todo-wrap">
<TodosHead @addTodos='addTodos'/><!--@addTodo:自定义事件名,"addTodo" 回调函数-->
<TodosList :todos="todos"/>
<TodosFoot>
<input type="checkbox" v-model="checkAll" slot="check"/>
</TodosFoot>
</div>
TodosFoot.vue
<div class="todo-footer">
<label>
<slot name="check"></slot>
</label>
<span>
<span>已完成{{completeSize}}</span> / 全部{{todos.length}}
</span>
<button class="btn btn-danger" v-show="completeSize" @click="deleteAllCompleted">清除已完成任务</button>
</div>
14 抽取功能模块为工具类
工具类storageUtil.js
/*
向local中存储数据的工具模块
1. 向外暴露一个函数(功能)
只有一个功能需要暴露
2. 向外暴露一个对象(包含多个功能)
有多个功能需要暴露
*/
const TODOS_KEY='todos_key'
export default {
saveTodos(todos){
window.localStorage.setItem(TODOS_KEY),JSON.stringify(todos)
},
readTodos(){
return JSON.parse(window.localStorage.getItem(TODOS_KEY) || '[]')
}
}
//在App.vue中引入
import storageUtil from './util/storageUtil.js'
//data中获取方法
todos: storageUtil.readTodos() //封装工具类
todos: storageUtil.readTodos() //封装工具类
15vue-ajax(axios 的使用)
下载插件
npm install axios --save
// 引入模块
import axios from 'axios'
// 发送 ajax 请求
mounted() {
const url='https://api.github.com/search/users?q=aaaa'
axios.get(url).then(response =>{
//成功
const result=response.data
const items= result.items[0]
this.login=items.login
this.refUtl=items.html_url
}).catch(error => {
alert('请求失败!')
})
},
16 vue-router路由
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转;
中文文档
安装
//下载
npm install vue-router --save
16.1使用步骤
- VueRouter(): 用于创建路由器的构建函数
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) //用于创建路由器的构建函数
export default new VueRouter({
// 多个配置项
})
- 路由配置
routes:[
{
//一般路由
path: '/about',
component: About
},
{
path: '/home',
component: Home,
//嵌套的子路由
children:[
{
path: '/home/news',
component: News
},
{
path: '/home/message', //或者写为path: 'message',
component: Message
},
{
path: '/',
redirect: '/home/news'
}
]
},
{
//自动跳转路由
path: '/',
redirect: '/about'
},
]
- 注册路由器 main.js
import router from './router'
new Vue({
router
})
- 使用路由组件标签
<!--生成路由链接 to----路由路径-->
<router-link to="/about" class="list-group-item">About</router-link>
<router-link to="/home" class="list-group-item">Home</router-link>
<!--keep-alive缓存路由组件对象, 可以提高用户体验-->
<keep-alive>
<!--用来显示当前路由组件界面-->
<router-view></router-view>
</keep-alive>
16.2向路由组件传递数据
16.2.1 路由路径携带参数(param/query)
- 配置路由
children: [
{
path: '/home/message/messageDetal/:id',
component: MessageDetal
}
]
- 路由路径
<li v-for="message in messages" :key="message.id">
<router-link :to="`/home/message/messageDetal/${message.id}`">{{message.title}}</router-link>
</li>
- 路由组件中读取请求参数
this.$route.params.id
16.2.2 属性携带数据
父类
<!--显示当前组件 msg自定义的参数-->
<router-view msg="abc"></router-view>
子类
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
props: {
msg: String //接收属性前,先声明
},
}
</script>
16.3 缓存路由组件对象
- 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
- 如果可以缓存路由组件对象, 可以提高用户体验
<keep-alive>
<router-view></router-view>
</keep-alive>
16.4命名路由
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',//命名
component: User
}
]
})
16.5 路由导航
命名路由后:
<router-link :to="`/home/message/messageDetal/${message.id}`">{{message.title}}</router-link>
等同于
<router-link :to="{ name: 'messageDetal', params: { id: `${message.id}` }}">{{message.title}}</router-link>
例子
<template>
<div>
<h1>about</h1>
<hr>
<p>{{msg}}</p>
<input type="text" @keyup.enter="clickEnter">
</div>
</template>
<script>
import router from '../router'
export default {
props: {
msg: String
},
methods: {
clickEnter(){
const userId=1*1
router.push({path:`home/message/messageDetal/${userId}`})
//router.push({ name: 'messageDetal', params: { id: `${userId}` }})
}
},
}
</script>
链接跳转没问题
16.5.1 其他API
- this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
-
this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
-
this.$router.back(): 请求(返回)上一个记录路由
-
this.$router.go(-1): 请求(返回)上一个记录路由
-
this.$router.go(1): 请求下一个记录路由
<template>
<div>
<ul>
<li v-for="message in messages" :key="message.id">
<!-- <router-link :to="`/home/message/messageDetal/${message.id}`">{{message.title}}</router-link> -->
<router-link :to="{ name: 'messageDetal', params: { id: `${message.id}` }}">{{message.title}}</router-link>
<button @click="pushShow(message.id)">push</button>
<button @click="replaceShow(message.id)">replace</button>
</li>
</ul>
<button @click="$router.back()">返回</button>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
data()
{
return {
messages: []
}
},
mounted()
{
window.setTimeout(() =>
{
const messages = [
{
id: 1,
title: 'message01'
},
{
id: 2,
title: 'message02'
},
{
id: 3,
title: 'message03'
}
]
this.messages = messages
}, 1000)
},
methods: {
pushShow(id)
{
this.$router.push(`/home/message/messageDetal/${id}`)
},
replaceShow(id)
{
this.$router.replace(`/home/message/messageDetal/${id}`)
},
},
}
</script>
特殊
1.filter过滤
dotos为数组 字段complete为boolean类型
2.forEach 循环
todo中complete赋值为check
3.unshift()
给数组添加todo对象并放在第一个
4.splice()
删除数组中下标为index的,1表示个数
5.watch监听
官方文档
setItem(key,walue)
getItem(key)
跟集合map一样
会缓存,重新运行就没有了
6. @keyup.enter
为click事件 回车键确认
7. 鼠标移动事件
onmouseenter 鼠标移动进来
onmouseleave 鼠标移动出范围
8.reduce() 数组的计算方法
测试代码
有需要可以去github自己下载
测试代码