继续深入Vue
本节我们继续深入Vue的核心部分内容
收集表单数据
Vue管理各类表单元素的值示例如下
<body>
<div id="root">
<form>
账号:<input type="text" v-model="account"> <br/><br/>
密码:<input type="password" v-model="password"> <br/><br/>
性别:
男<input type="radio" name="sex" v-model="sex" value="male">
女<input type="radio" name="sex" v-model="sex" value="female"> <br/><br/>
爱好:
学习<input type="checkbox" v-model="hobby" value="study">
打游戏<input type="checkbox" v-model="hobby" value="game">
吃饭<input type="checkbox" v-model="hobby" value="meal">
所属校区
<select v-model="city">
<option value="">请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
<br/><br/>
<textarea v-model="other"></textarea>
<br/><br/>
同意<input type="checkbox" v-model="arg">
<button>提交</button>
</form>
</div>
<script>
const vm=new Vue({
el:'#root',
data:{
account:'',
password:'',
sex:'',
hobby:[],
city:'',
other:'',
arg:false,
}
})
</script>
</body>
v-model也有修饰符,如下:
1.number表示输入的是数字(类型转换)
2.lazy表示失去焦点才收集
3.trim去除前后空格
内置指令
v-text:向其所在的标签插入文本(会覆盖标签内的文本内容)注意:不解析字符串
<div v-text="name"></div>//name是一个data里的属性
v-html:与v-text类似都可以插入文本,但是v-html会解析html元素
v-once:只被Vue渲染一次
<h2 v-once>{{name}}</h2>
v-pre:跳过节点的编译过程,可以用它跳过没有指令语法,插值语法的节点,会加快编译过程,使用跟v-once一样,也没有值
自定义指令
借助directives配置项,我们可以配置新的指令
directives里面直接写函数即可,该函数接受两个参数,分别是对应的元素的真实DOM,和一个绑定对象,绑定对象我们更关注的是绑定对象的value属性,它决定了调用该指令的节点的文本内容
directives里函数调用的时机:
1.指令与元素成功绑定时
2.指令所在的模板被重新解析时调用
示例1:
<body>
<div id="root">
<h2 v-big="n"></h2>
</div>
<script>
const vm=new Vue({
el:'#root',
data:{
n:1
},
directives:{
big(rdom,binding){
rdom.innerText = binding.value*10
}
}
})
</script>
</body>
示例2:设计一个v-fbind指令,有默认获取焦点并绑定值的功能
<body>
<div id="root">
<h2 v-big="n"></h2>
<input type="text" v-fbind:value="">
</div>
<script>
const vm=new Vue({
el:'#root',
data:{
n:1
},
directives:{
big(rdom,binding){
rdom.innerText = binding.value*10
},
//对象式写法
fbind:{
//绑定成功时调用
bind(rdom,binding){
rdom.innerText=binding.value
},
//指令所在元素被插入页面时
inserted(rdom,binding){
rdom.focus()
},
//指令所在模板被重新解析时
update(rdom,binding){
rdom.innerText=binding.value
}
}
}
})
</script>
</body>
生命周期
Vue的生命周期如下:
1.beforeCreate:最早的初始化,还没开始数据代理
2.created:数据代理、数据监测,此时,已经可以访问data和methods
3.beforeMount:还未解析DOM
4.mounted:DOM解析完成,页面显示出内容
5.beforeUpdate:页面是旧的,数据是新的
6.updated:页面与数据同步完成
7.beforeDestroyed:data,methods这些东西即将销毁
8.destroyed:全部销毁
组件化编程
创建组件:
注意点:不能写el,data要写成函数
示例如下:
<body>
<div id="root">
<school></school>
</div>
<script>
const school=Vue.extend({
template:`
<div>
<h2>{{name}}</h2>
</div>
`,
data(){
return{
name:'Java'
}
}
})
const vm=new Vue({
el:'#root',
components:{
school,
}
})
</script>
</body>
Vue.component('xxx')可以全局注册组件
定义组件时规定name,这个name是开发者工具显示的名字,跟注册用的名字没有区别
不用Vue.extend直接写配置对象也可以
每调用一次Vue.extend,都会调用一次VueComponent构造函数
但是,每次调用,返回的对象都是一个新的对象
组件中的data,methods,watch,computed中的函数,它们的this都是VueComponent
Vue的实例对象与VueComponent实例对象关系:
1.二者所拥有的东西几乎全部都是一样的
2.vm中可以有el配置项,vc中不可以
Vue的原型对象就是VueComponent的原型对象的原型对象
render:用于解析模板
ref属性
ref被用于给元素或者子组件注册引用信息
ref可以理解为id的代替,可以用于获取DOM
如果放在了组件上,我们可以获取组件的实例对象(vc)
示例如下:
<template>
<div>
<h1 v-text="msg" ref="title"></h1>
<button @click="showDOM">点我获取DOM</button>
<SchoolInfo/>
</div>
</template>
<script>
import SchoolInfo from './components/SchoolInfo.vue'
export default {
name: 'App',
data(){
return {
msg:'欢迎!'
}
},
components: {
SchoolInfo,
},
methods:{
showDOM(){
console.log(this.$refs.title)
}
}
}
</script>
<style>
</style>
props配置
props可以给组件传数据,写法上,只要当作属性放在组件标签上面就可以了,如果加:,可以转换为JS表达式,props不用数组接受而是写对象式可以限制类型,不符合类型会报错
App.vue
<SchoolInfo name="黑马" address="南京"/>
SchoolInfo.vue
<script>
export default {
name:'SchoolInfo',
data(){
return {
msg:'欢迎'
}
},
//props:['name','address'],
props:{
name:{
type:String,
required:true
},
address:{
type:String,
default:'北京'
}
}
}
</script>
props优先级比data高,注意不要重名,props不能使用保留字(比如'key')
另外,不要直接修改props,如果要修改的话最好配一个值相等的data属性
mixin混入
mixins混入配置项,可以导入把外部js的东西混入进去(以数组形式)
作用:mixin实现了复用配置项
混合不会覆盖冲突数据,但是生命周期会均生效
用Vue.mixin可以全局混入
插件
本质就是一个对象,但是必须要有install方法
使用插件时,可以用Vue.use这个API
install函数接受一个参数,就是Vue构造函数本身,除此以外,我们在use是,还可以传任意参数
那么我们就可以实现给Vue原型上加方法,定义指令,定义混入等等
export default {
install(){
console.log('hahah')
}
}
scoped属性
在style标签上添加scoped属性,可以避免css重名冲突,也就是互不干扰
当然Vue里,我们添加lang属性,可以用less语法,但是要安装less-loader
浏览器的本地存储
下面展示向本地存储操作数据:
<body>
<button onclick="saveData()">点我存数据</button>
<button onclick="readData()">点我读数据</button>
<button onclick="deleteData()">点我删数据</button>
<script>
let p={name:'张三',age:18}
//写
function saveData(){
localStorage.setItem('msg','hello')
localStorage.setItem('num',666)
localStorage.setItem('person',JSON.stringify(p))//对象必须转换为JSON
}
//读
function readData(){
console.log(localStorage.getItem('msg'))
}
//删除
function deleteData(){
localStorage.removeItem('msg')
}
//清空
function clearData(){
localStorage.clear()
}
</script>
</body>
注意:读取的key不存在,会返回null
localStorage即使浏览器被关闭也不会消失
sessionStorage的API与localStorage一样,但是,浏览器被关闭就没了,localStorage则会在用户清缓存才消失
组件自定义事件
我们也可以自定义类似click,change这样的事件,但是,是给组件绑定的
绑定的时候,我们可以使用v-on:事件名称="demo"的方式绑定
也可以使用this.on('事件名称',回调函数)
触发用this.$emit('事件名称',数据)
解绑用this.$off('事件名称')多个事件解绑,写进数组里
全局事件总线
可以实现任意组件通信
本质就是找一个X作为中间人,每个组件都在X身上放一个自定义事件,以此来互相交流数据
因此,这个X就必须放在所有组件都能看到的地方,也就是Vue的原型对象上(一个重要关系那里讲过)
除此以外,X也必须能调用on,$off
on,bus
注意,组件在mounted绑定了自定义事件后,最好在beforeDestroy里面解绑
消息订阅与发布
消息订阅与发布,也是一种组件间通信的方式
首先,我们需要安装pubsub-js这个库
当然,mounted里面订阅消息,beforeDestroy要取消订阅,另外,订阅消息的回调函数需要用箭头函数
$nextTick
this.nextTick(function(){})里面的回调函数会在下一次碰到DOM更新时执行