Vue组件学习相关
组件相关知识
①组件注册:变量名大小写不敏感,全局注册共有三种方式:
Ⅰ:camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名)
Vue.component('mycom1', {
props: ['myCom'], // 在 JavaScript 中是 驼峰
template: '<h3>第一种方式</h3>'
})
<!-- 在 HTML 中是 短横线-->
<mycom1 my-com="hello!"></mycom1>
Ⅱ:在外部template标签定义组件并引用id:
//定义
<template id="tmp1"></template>
Vue.component('mycom2',{
template:'#tmp1',
})
//使用
<mycom2></mycom2>
Ⅲ:使用Vue.extend注册
//定义
Vue.component("mycom3",Vue.extend({
template:'<h3>这是第三种方式</h3>'
}));
//使用
<mycom3></mycom3>
②传递prop:
⑴除了传递字符串格式,其他对象数组数字等都需要用v-bind:
作为表达式传递。
⑵传入一个对象的所有属性,可使用无参数无引号的v-bind
来传递。
如:<blog-post v-bind="post"></blog-post>
⑶单向下行绑定,父级 prop 的更新会向下流动到子组件,应当防止子组件修改父级prop。可在子组件中定义初始值接受prop,再进行操作。
☆对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
(4)子组件向父组件传参:通过v-on(@)
监听事件的方式带参数过去。
//子组件methods方法中触发父组件函数textChange
<button @click="handleClick"></button>
methods:{
handleClick(){
this.$emit("textChange","要传递的参数")//可通过emit的第二个参数往父组件传值
}
}
//父:
<ul-com :list="list" @textChange="handleTextChange"></ul-com>
(5)父组件传参
给子组件:数据用prop和v-bind。方法用v-on/@。
//父组件:
<List-Item :list="list">
//子组件:
props:{
list:Array
}
③pros的type类型值:String
Number
Boolean
Array
Object
Date
Function
Symbol
④prop 验证:
Vue.component('my-component', {
props: {
propA: Number,// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证
propB: [String, Number], // 多个可能的类型
propC: {
type: String,
required: true,// 必填的字符串
},
propD: {
type: Number,
default: 100, // 带有默认值的数字
},
propE: { // 带有默认值的对象
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
propF: { // 自定义验证函数
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
⑤组件可以接收未定义prop的任意变量,且会自动添加到根元素上。
⑥父级提供给组件的值会替换掉组件内部设置好的值,而class
和style
属性会合并传入的值和原有设定的值。
⑦禁用变量继承:inheritAttrs: false
⑧组件切换使用标签component :is="name"
,name是组件的名称。
自定义组件相关知识
①子组件可以使用 $emit
触发父组件的自定义事件。
②事件名会自动转换为小写。
③自定义组件的 v-model:
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > `
})
使用:<base-checkbox v-model="lovingVue"></base-checkbox>
④将原生事件绑定到组件,可以使用 v-on
的 .native
修饰符,
即:<base-input v-on:focus.native="onFocus"></base-input>
⑤.sync
修饰符是update:myPropName
的缩写,可实现安全的双向绑定。用法:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
//两者相等
<text-document v-bind:title.sync="doc.title"></text-document>
<slot>
插槽相关知识
①在组件中写入<slot></slot>
,则在引用该组件时,可以包含任何模板代码:
<navigation-link url="/profile">
<!-- 添加一个 Font Awesome 图标 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>
②具名插槽,即在引用绑定多个<slot></slot>
的组件时,使用v-slot
的参数形式提供其名称达到一个个插的效果。★ v-slot
只能添加在 <template>
上。
//base-layout组件
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
//v-slot写法
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
③作用域插槽,可让父级读取子组件中的user
数据。
//current-user组件
<span>
<slot v-bind:user="user">
{ { user.lastName }}
</slot>
</span>
//插槽prop
<current-user>
<template v-slot:default="slotProps">
{ { slotProps.user.firstName }}
</template>
</current-user>
⑴默认插槽可去掉<template>
采用在<current-user>
上写v-slot
的缩写形式,但有具名插槽时必须如上分别写出来。
⑵解构插槽prop且重命名:
<current-user v-slot="{ user: person }">
{ { person.firstName }}
</current-user>
④具名插槽的缩写:v-slot用#
,#
后必须接参数,如#default
,#header
等。
动态组件
使用<keep-alive>
包裹的组件实例能在第一次创建时缓存下来。
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
边界问题
①$root
可以访问所有vue实例中的属性和方法。
②$parent
可以用来从一个子组件访问父组件的实例。
ref相关知识 ref获取到的是原生js的dom元素或者组件本身
①ref绑定在相关组件上如:<uni-popup ref="auth"></uni-popup>
,在引入该组件的页面通过this.$refs.auth.clickLogin
调用对应的方法。最常用。
②ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。比如在生命周期 mounted(){}
钩子中调用,或者在 this.$nextTick(()=>{})
中调用。
路由vue-router
①创造路由,传递一个配置对象:使用前需导入vue-router.js
//组件的模板对象
var login = {
template:'<h1>登录组件</h1>'
};
var routerObj = new VueRouter({
//routes表示路由的匹配规则
routes:[//component表示显示path路径匹配到的组件的模板对象
{ path:'/',redirect:'/login'},
{ path:'/login',component:login}
],
linkActiveClass:'myactive'
})
var vm = new Vue({
el:'#app',
data:{ },
methods:{ },
router:routerObj //路由规则对象注册到vm实例上,监听url地址的变化
})
<div id="app">
//必须在html中定义router-view,作为组件显示的占位符
<router-view></router-view>
//<a href = '#/login'>登录</a>
<router-link to="/login" tag="span"></router-link> //默认渲染a标签,tag可以改变渲染的标签
</div>
//给选中的组件变化样式
//active-class可以在router-link标签上添加属性,默认值由路由的构造选项linkActiveClass来配置
<style>
.router-link-active{
color:red;
font-weight:800;
font-style:italic;
}
.myactive{ ...}
</style>
②给组件切换添加过渡效果:组件外可直接加transition
标签设置切换动画效果。mode="out-in"
常用。
<transition mode="out-in">
<router-view></router-view>
</transition>
<style>
.v-enter,v-leave-to{
opacity:0;
transform:translateX(140px);
}
.v-enter-active,v-leave-active{
transition:all 0.5s ease;
}
</style>
③路由规则中定义参数:
var login = {
template:'<h1>登录组件</h1>',
create(){ //组件生命周期钩子
console.log(this.$route.query) //query获取
}
};
var register = {
template:'<h1>注册组件</h1>',
create(){ //组件生命周期钩子
console.log(this.$route.query) //query获取
console.log(this.$route.params)//params获取
}
};
var routerObj = new VueRouter({
routes:[
{ path:'/',redirect:'/login'},
{ path:'/login',component:login},
{ path:'/register/:id/:name',component:register},//id和name都是key的键名
]
})
var vm = new Vue({
el:'#app',
data:{ },
methods:{ },
router:routerObj
})
<div id="app">
<router-view></router-view>
<router-link to="/login?id=122"></router-link>//query方式传参
<router-link to="/login/12/张三"></router-link>//params方式传参
</div>
③使用children属性实现路由嵌套:
<template id='tmp1'>
<div>
<h1>这是account组件</h1>
<router-link to="/account/login"></router-link>
</div>
</template>
var account = {
template:'#tmp1',
};
var login= {
template:'<h3>登录</h3>',
};
var routerObj = new VueRouter({
routes:[
{
path:'/account',
component:account,
children:[
{ path:'login',component:login}//children的path不以/开头,否则永远以跟路径开头
]
},
//{path:'/account/login',component:login},子路由不能这么写
]
})
var vm = new Vue({
el:'#app',
data:{ },
methods:{ },
router:routerObj
})
<div id="app">
<router-view></router-view>
<router-link to="/account"></router-link>
</div>
④使用命名路由视图:
<template id='tmp1'>
<div>
<h1>这是header组件</h1>
</div>
</template>
var header= {
template:'#tmp1',
};
var main = {
template:'<h3>中央</h3>',
};
var routerObj = new VueRouter({
routes:[
{
path:'/',
components:{
'default':header,
'main':main,
},
},
]
})
var vm = new Vue({
el:'#app',
data:{ },
methods:{ },
router:routerObj
})
<div id="app">
<router-view></router-view>
<router-view name="main"></router-view> //这是一个值
</div>
常用属性
①input标签立定义@keyup来监听输入事件的改变。
②vm实例中使用watch:{}
属性耶可以监视data数据的改变,出发watch中对应的function处理函数。
var vm = new Vue({
el:'#app',
data:{
firstname:'',
},
methods:{ },
watch:{
'firstname':function(newVal,oldVal){
console.log('监听到fistname的变化。')
},
'$router.path':function(newVal,oldVal){
console.log('监听到路由路径的的变化。')
}
}
})
③vm实例的computed:{}
可以定义计算属性,计算属性本质是一个方法,但调用时把他当成属性在相应的html里调用。
var vm = new Vue({
el:'#app',
data:{
firstname:'',
},
methods:{ },
computed:{
'fullname':function(){ //function内部涉及的任何data数据发生变化都会重新计算该计算属性的值
return firstname + '-';
}
},
})
④watch:{}
,methods:{}
和computed:{}
的对比:
(1)watch
是一个对象,键是需要观察的表达式,值是回调函数,里面使用赋值方式;而computed
里面的计算属性必须return一个值。
(2)computed
只适合简单的数据操作,不需要做大量的业务逻辑;业务逻辑交给methods
或watch
。
(3)computed
的结果会被缓存,主要当成属性使用。
还没有评论,来说两句吧...