[toc]
vue 基础
1.data 数据监控
<div id="app">
{{info.address}} {{arr}}
</div>
let vm = new Vue({
el: '#app',
data : { //存放数据
msg : 'hello',
info: {xxx:'xxx'},
arr : [1, 2, 3, 4]
}
})
2.vue 数据劫持 Object.defineProperty
- 如果属性不存在 默认后增加的内容 并不会刷新视图
- 数组调用push 是无效的 Object.defienProperty 不支持数组的
- 数组不能通过长度修改 也不能通过数组的索引进行更改
// 数据源
let obj = {
name : 'come',
age : {
age : 19
}
}
function observer(obj){
if(typeof obj == 'object'){
for(let key in obj){
defineReactive(obj, key, obj[key]);
}
}
}
function defineReactive(obj, key, value){
observer(value); //判断value是不是一个对象,如果是对象,继续监控
Object.defineProperty(obj, key, {
get(){
return value;
},
set(val){
observer(val);
console.log('数据更新了');
value = val;
}
})
}
observer(obj);
// obj.age = {name:1};
// vue 把 这个数组上的所有方法 都重写了
let arr = ['push','slice','shifit','unshift']
arr.forEach(method=>{
let oldPush = Array.prototype[method];
Array.prototype[method] = function(value){
console.log('数据更新了111')
oldPush.call(this,value);
}
})
obj.arr = [];
obj.arr.push(6);//会更新数据
obj.arr.length--;//不会更新数据
3.vue实例上的方法
1.vm.$el
console.log(vm.$el)
//<div id="app">
// [
// 5,
// 6,
// 7
//]
// </div>
2.vm.$options
对象参数
3.vm.$nextTick
- 数据变化后更新视图操作是异步执行的
- 在同一事件循环中的数据变化后,DOM完成更新,立即执行nextTick(callback)内的回调。
vm.$nextTick(()=>{
console.log(vm.$el.innerHTML);
console.log(vm.$options);
})
4.vm.$watch
watch是观察一个特定的值,当该值变化时执行特定的函数
vm.$watch('info.xxx', function(newValue, oldValue){
console.log(newValue, oldValue);
})
5.vm.$set
把数据都代理给了vm
vm.$set(vm.info,'address','zf');
vm.arr = [1,3,4]
4.模板template
取值表达式 可以 运算 , 取值 , 做三元
<div id="app">
<!-- 取值表达式 可以 运算 , 取值 , 做三元 -->
{{1+1}}
{{msg}}
{{flag?'ok':'no'}}
{{ {name:1} }}
{{ 'msg' + 'hello'}}
</div>
let vm = new Vue({
el:'#app',
data:{
msg:'hello',
flag:true
}
});
5.directive
v-html v-once v-if v-show
<div id="app">
<!-- 内部会进行缓存 以后使用的都是缓存里的结果 -->
<div v-once>{{msg}}</div>
<!-- v-html innerHTML XSS攻击 不能将用户输入的内容展现出来 内容必须是可信任的-->
<div v-html="d"></div>
<!-- v-if 如果不成里 dom就会消失 -->
<!-- v-if 控制的是 dom 有没有 v-show控制的是样式 -->
<!-- v-show不支持template -->
<template v-show="flag">
<div>hello</div>
<div >123</div>
</template>
<div>312</div>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'hello',
d:'<h1>hello</h1>',
flag:false
}
});
</script>
v-for
尽量不要使用index做为key
<div v-for="(fruit,index) in fruits" :key="index">
<div v-if="index%2">{{fruit}}</div>
<div v-else>{{index}}</div>
</div>
<div v-for="(value,key) in info">
{{value}}
</div>
let vm = new Vue({
el:'#app',
data:{ // for value of [1,2,3]
fruits:['🍌','🍏','🍊'],
info:{name:'珠峰',age:10,address:'回龙观'},
flag:true
}
});
v-model
let vm = new Vue({
data:{
val:0,
c:'d',
msg:'hello',
selectValue:[],
radioValue:'男',
checkValues:[],
checkValue:true,
lists:[{value:'菜单1',id:1},{value:'菜单2',id:2},{value:'菜单3',id:3}]
},
methods:{
fn(e,a){
alert(1)
}
}
}).$mount('#app');
<input type="text" :value="msg" @input="e=>msg=e.target.value">
<!-- v-model 是 @input + :value 的一个语法糖 -->
<input type="text" v-model="msg">
{{msg}}
select
<select v-model="selectValue" multiple>
<option value="0" disabled>请选择</option>
<option v-for="(list,key) in lists" :value="list.id">{{list.value}}</option>
</select>
{{selectValue}}
radio
<!-- radio 可以根据v-model来进行分组-->
男:<input type="radio" v-model="radioValue" value="男">
女:<input type="radio" v-model="radioValue" value="女">
{{radioValue}}
checkbox
<!-- 全选 多选 true/ false -->
<input type="checkbox" v-model="checkValues"> {{checkValue}}
<!-- 爱好 -->
<br>
游泳:<input type="checkbox" v-model="checkValues" value="游泳">
健身<input type="checkbox" v-model="checkValues" value="健身">
{{checkValues}}
修饰符 .number .trim
<input type="text" v-model.number.trim="val"> {{val}}
修饰符 键盘修饰符 鼠标的修饰符
<input type="text" @keyup.ctrl.enter="fn">
属性绑定 : v-bind: 绑定样式 class style 对象 数组(多个) 数组里可以放对象
<div class="abc" :class="{b:true}">
你好
</div>
<div class="abc" :class="['a','b',c]">
你好
</div>
<div style="color:red" :style="{background:'blue'}">xxx</div>
<div style="color:red" :style="[{background:'red',color:'blue'}]">xxx</div>
6.computed
computed 和 watch 区别 watch可以支持异步
computed : {
// fullName(){
// return this.firstname + this.lastname
// }
}
computed 全选 反选
全选 <input type="checkbox" v-model="checkAll">
<input type="checkbox" v-for="(item,key) in checks" v-model="item.value" :key="key">
let vm = new Vue({
el:'#app',
data:{
checks:[{value:true},{value:false},{value:true}],
},
computed:{
checkAll:{
get(){
return this.checks.every(check=>check.value)
},
set(value){ // 双向绑定数据
this.checks.forEach(check =>check.value = value);
}
}
}
})
7. 生命周期
<div id="app">
{{a}} {{b}}
</div>
let vm = new Vue({
el:'#app',
data:{
a:1,
b:1
},
beforeCreate(){ // 钩子函数 beforeXXX xxxxed
console.log(this,this.$data); // 初始化自己的生命周期 并且 绑定自己的事件
},
created(){ // 如果想调用ajax
console.log(this.$data); // 可以获取数据和调用方法
},
beforeMount(){ // 第一次调用渲染函数之前
console.log('渲染前')
},
template:'',
mounted(){ // 获取真实dom 因为页面已经渲染完了
console.log('渲染后',this.$el.innerHTML);
this.a = 100;
this.timer = setInterval(()=>{
})
},
beforeUpdate(){
this.b = 200;
console.log('更新前')
},
updated(){ // 一般不要操作数据 可能会导致死循环
console.log('更新后');
},
beforeDestroy(){
// 当前实例还可以用
clearInterval(this.timer);
console.log('销毁前')
},
destroyed(){
// 实例上的方法 监听都被移除掉
console.log('销毁后')
}
}); // 第一种 路由切换 手动销毁
vm.$destroy();
8. 组件
组件开发的优点
- 开发的优点
- 方便协作
- 方便维护
- 复用 (数据是根据传入的数据展示)
8.1 组件的定义方式
全局组件 局部组件
全局组件
Vue.component('my-button',{
data(){ // 为了每个组件的数据 互相不影响
return {msg:'点我啊'}
},
template:`<button>{{msg}}</button>`
});
局部组件
let vm = new Vue({ // 根实例
el:'#app',
components:{
'MyButton':{
data(){
return {msg:'点我啊'}
},
template:`<button>{{msg}}</button>`
}
}
});
8.2 组件的数据
组件的数据必须是函数形式
'MyButton':{
data(){
return {msg:'点我啊'}
},
template:`<button>{{msg}}</button>`
}
8.3 组件的属性应用以及校验
8.3.1 属性应用
<my-button :msg="content" a="1" b="2"></my-button>
let vm = new Vue({
el: '#app',
data : {
content : '点我啊'
},
components : {
'MyButton' : {
props : ['msg', 'a'],
template : `<div> my-button {{msg}} {{a}}</div>`
}
}
})
组件是驼峰,写成html要变成横杠
8.3.2 属性校验
<my-button :msg="content" :a="1" b="2"></my-button>
let vm = new Vue({
el: '#app',
data : {
content : '点我啊'
},
components : {
'MyButton' : {
//props : ['msg', 'a'],
props : {
msg : {
type : String,
default : '111'
},
a :{
type : Number,
default : '111'
}
},
template : `<div> my-button {{msg}} {{a}}</div>`
}
}
})
8.3.3 批量传入数据
let vm = new Vue({
el: '#app',
data : {
content : '点我啊'
},
components : {
'MyButton' : {
mounted(){
console.log(this.$attrs);
},
inheritAttrs: false,
template : `<div> my-button {{this.$attrs.msg}}my v-bind="$attrs"></my></div>`,
components : {
'my' : {
props : ['a', 'b'],
template : `<span>{{a}} {{b}}</span>`
}
}
}
}
8.4 事件应用
儿子要调用父亲的方法 有三种方式
<my-button @click="change" @mouseup="change"></my-button>
let vm = new Vue({
el:'#app',
data:{
content:'点我啊'
},
methods:{
change(){
alert(1);
}
},
components:{
'MyButton':{ // v-bind=$attrs v-on=$listeners 绑定所有的方法
template:`<div>
<button @click="$listeners.click()">点我啊</button>
<button @click="$emit('click')">点我啊</button>
<button v-on="$listeners">点我啊</button>
</div>`
}
}
});
8.5 children
<collapse>
<collapse-item title="react">内容1</collapse-item>
<collapse-item title="vue">内容2</collapse-item>
<collapse-item title="node">内容3</collapse-item>
</collapse>
// 平级通信 $parent 获取父组件的实例 $children获取所有的儿子
Vue.component('Collapse',{
mounted(){
console.log(this._uid);
},
methods:{
cut(childId){ // 只要儿子点击了 我就要知道当前点击的是谁
this.$children.forEach(child => {
if(child._uid !== childId){
child.show = false;
}
});
}
},
template:`<div class="wrap">
<slot></slot>
</div>`
});
Vue.component('CollapseItem',{
props:['title'],
data(){
return {show:false}
},
methods:{
change(){
this.$parent.cut(this._uid);
this.show = !this.show;
}
},
template:`<div>
<div class="title" @click="change">{{title}}</div>
<div v-show="show">
<slot></slot>
</div>
</div>`
})
// 手风琴效果 折叠菜单效果
let vm = new Vue({
el:'#app',
mounted(){
console.log(this._uid)
}
})
8.6 Provide inject
Vue.component('my',{
inject:['a'],
template:"<div>{{a}}</div>"
})
let vm = new Vue({
el:'#app',
provide:{ // 在根上提供了一个a属性 ,所有的子组件 都可以获取
a:1
},
mounted(){
console.log(this._uid)
}
})
8.7 ref特性
ref不能给多个元素设置相同的ref 只识别一个
let vm = new Vue({
el:'#app',
mounted(){
console.log(this.$refs.my);
console.log(this.$refs.com.show());
},
components:{
'myComponent':{
methods:{
show(){
alert(1);
}
},
template:`<div>my-component</div>`
}
}
});
8.8 slot
1.具名插槽
<div id="app">
<child>
<header slot="header">header</header>
<footer slot="footer">footer</footer>
</child>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<!-- 只要模板中使用了数据,必须在实例上声明 -->
<script>
let vm = new Vue({
el: '#app',
components:{
'child':{
data(){
return {arr:[1,2,3]}
},
template:`<div>
<slot name="header">default header</slot>
<div>content</div>
<slot name="footer">default footer</slot>
</div>`
}
}
})
// 把数据都代理给了vm
</script>
2.作用域插槽
<child>
<template slot-scope="props"><!--定义一个插槽,该插槽必须放在template标签内-->
<li>{{props.value}}</li><--!定义使用渲染方式-->
</template>
</child>
<child>
<template slot-scope="props">
<h1>{{props.value}}</h1><!--定义不同的渲染方式-->
</template>
</child>
Vue.component('child',{
data: function(){
return {
list:[1,2,3,4]
}
},
template: `<div>
<ul>
<slot v-for="value in list" :value=value>//使用slot占位
</slot>
</ul>
</div>`
})
var vm=new Vue({
el: '#root'
})
原文:https://blog.csdn.net/willard_cui/article/details/82469114
组件间通信
- 1.props和emit父亲组件向子组件传递数据通过prop传递,子组件传递数据给父组件是通过emit触发事件来做的
- 2.attrs和listenners
- 3.parent,children
- 4.$refs获取实例
- 5.父组件通过provider提供变量,然后在子组件通过inject来注入变量
- 6.envetBus平级组件数据传递,这种情况可以使用中央事件总线方式
- 7.vuex状态管理