ref 属性
ref 被用来给元素或子组件注册引用信息(id的替代者)
应用在 html 标签上获取的是真实 DOM元素 ,应用在组件标签上获取的是组件实例对象 vc。
1、如果给普通的dom元素使用,引用指向的是dom元素。
2、如果是给子组件使用,引用指向的是子组件的实例。
ref使用方式:
a.打标识:
<h1 ref="xxx"></h1>或<School ref="xxx"></School>
b.获取:
this.$refs.xxx
ref的三种用法:
1.ref加在普通的元素上,用this.ref.name获取到的是dom元素;
2.ref加在子组件上,用this.ref.name获取到的是组件实例,可以使用组件
的所有方法;
3.如何利用v-for和ref获取一组数据获取dom节点。
当v-for用于元素或者组件的时候,
引用信息将是包含dom节点或组件实例的数组;
关于ref注册时间的重要说明:
因为ref本身是作为渲染结果被创建的,
在初始渲染的时候,你不能访问它们--它们还不存在
!$refs也不是响应式的,因此你不应该试图用它在模板中做数据绑定。
props 配置项
props是 Vue 组件之间通信的一种方式,通过props,父组件可以向子组件传递数据,即:父组件可以通过组件标签上的属性值把数据传递到子组件中。子组件可以根据自己的属性和方法去渲染展示数据或执行某些操作。由于 props 是单向数据流的,它是只能从父组件传递到子组件的,而子组件是无法更改 props 的值的,只能由父组件来修改。这样就保证了组件的数据传递不会出现混乱和错乱的情况。
如何定义props?
在 Vue 组件中,需要通过配置 props 属性来定义组件的 props。在组件中添加 props 属性之后,就可以使用 props 选项接收从父组件传递的数据。
props传递数据:
<Demo name="xxx":age="18"/>这里age前加:通过v-bind使得里面的18是数字
props接收数据:
第一种方式(只接收)
props:['name','age']
第二种方式(限制类型)
props:{name:String,age:Number}
第三种方式(限制类型、限制必要性、指定默认值)
props:{
name :{
type:string,//类型
required:true,//必要性
default:'cess'//默认值
}
}
备注:
props是只读的,Vue 底层会监测你对 props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props 的内容到 data中,然后去修改 data 中的数据
props的使用场景
当我们需要在父组件和子组件之间进行数据传递时,就可以使用 Props。比如,在一个商品列表页面中,可以定义一个 ProductList 的父组件,子组件 ProductItem 可以通过 Props 接收父组件传递过来的产品信息,用于渲染商品列表。代码示例如下
在父组件 ProductList 中,定义一个产品列表,然后使用 v-for 指令遍历产品列表,将每个产品作为一个子组件 ProductItem 的 product props 传递给子组件:
<template>
<div>
<ProductItem v-for="product in products" :key="product.id" :product="product" />
</div>
</template>
<script>
import ProductItem from './ProductItem.vue'
export default {
components: {
ProductItem
},
data() {
return {
products: [
{
id: 1,
name: 'Product A',
price: 100,
description: 'This is product A'
},
{
id: 2,
name: 'Product B',
price: 200,
description: 'This is product B'
}
]
}
}
}
</script>
在子组件 ProductItem 中,通过 props 对象声明一个名为 product 的 props,然后通过模板插值,将父组件传递过来的产品信息进行渲染:
<template>
<div>
<h2>{{ product.name }}</h2>
<p>{{ product.description }}</p>
<p>Price: {{ product.price }}</p>
</div>
</template>
<script>
export default {
props: {
product: {
type: Object,
required: true
}
}
}
</script>
在上面的代码中,父组件 ProductList 将产品列表 products 传递给子组件 ProductItem 的 product props,子组件 ProductItem 接收并渲染产品信息。这样可以很容易地实现在一个商品列表页面中渲染商品列表。
属性验证
在vue中可以通过定义 props 对象的方式进行Props校验。
为了校验一个属性,可以在 props 对象中添加一个与该属性名称相同的属性,该属性的值为一个对象。这个对象可以包含以下选项:
type: 指定属性的类型。可以为 JavaScript 原生构造函数
(如 String、Number、Boolean)或自定义构造函数。
如果指定多个可选类型,可以使用数组 [String, Number] 的方式表示。
required: 指定该属性是否是必需的。如果该属性没有默认值,
并且父组件没有传递该属性,则会在控制台中打印警告。
default: 指定该属性的默认值。如果父组件没有传递该属性,
则使用默认值。如果 default 的值是对象或数组,必须将其设置为函数,
并在函数中返回它,以避免值之间的共享。
validator: 指定一个自定义验证器函数,用于在接收到 prop 的值时检查其有效性。
例如,下面的组件定义了一个名为 my-component 的组件,其中有一个 prop 名称为 age,类型为 Number,且必需:
<template>
<div>
<p>My age is: {{ age }}</p>
</div>
</template>
<script>
export default {
props: {
age: {
type: Number,
required: true
}
}
}
</script>
如果 my-component 在使用时没有传递 age 属性或 age 的值不是一个数字,则会在控制台中打印一个警告。如果正确设置了 prop,则会将其传递给组件,并在模板中进行渲染。
除了上面提到的选项之外,还可以通过 props 对象的 .default、.required、.type、.validator 属性来直接进行校验,例如:
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
message: {
default: 'default message',
required: true,
type: String,
validator: (value) => {
return value.length <= 10
}
}
}
}
</script>
在这个例子中,message 属性的默认值是 default message,必需且类型为 String,并且在传递给子组件时使用 validator 函数进行验证。在这个例子中,验证器函数检查 message 是否超过 10 个字符,如果超过,将返回 false 并打印一个警告。
mixin 混入
什么是mixin混入?
Vue.js官方解释:混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue
组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
通俗的来说:
如果多个组件有很多相同的功能,那么就可以把这些相同的功能抽离出来写成一个混入对象,如有需要直接引入使用混入即可,引入后混入中在data中定义的数据,methods中定义的方法等都会成为组件中自己的数据和方法,相当于将混入对象中的数据、方法等合并到组件身上,可以减少代码的冗余。
mixin 混入功能:
可以把多个组件共用的配置提取成一个混入对象
mixin 混入的写法和使用
混入对象和组件对象基本是相同,都有data、method和一系列生命周期钩子函数。
// 1. 创建mixin.js并导出混入对象
export default {
data() {
return {
str: 'mixin'
}
},
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
....
methods: {},
...
}
// Vue组件使用
<script>
// 2. 引入mixin.js
import mixin from '../mixin'
export default {
// 3. 使用混入对象
mixins: [mixin],
mounted() {
console.log(this.str);
}
};
</script>
mixin 混入的规则
- 数据重复以组件数据为准
数据对象进行合并,其中的基本数据类型在和组件的数据发生冲突时以组件数据优先,
组件中的数据会覆盖混入对象的数据。
// mixin.js
data() {
return {
num: 1
}
}
// Vue组件
data() {
return {
num: 2
}
}
上述代码中混入对象和Vue组件都定义了一个名为num的数据,
在引入并使用混入后,num会以组件自身定义的为准,num的值为2。
- 引用数据类型会进行深参差的递归合并
数据对象中如果有引用数据类型,引用数据类型会进行深参差的递归合并。
// mixin.js
data() {
return {
person: {
a: 1
}
}
}
// Vue组件
data() {
return {
person: {
b: 2
}
}
}
上述代码中混入对象和Vue组件都定义了一个名为person的对象,在引入并使用混入后,person对象进行了类似于Object.assign方法,person的值为{ a:1, b: 2 }。
- 混入的生命周期优先于组件生命周期执行
生命周期钩子函数混合为一个数组,当使用组件时,组件的函数和混和的函数都执行,混入中的函数会先执行,组件的函数后执行。
// mixin.js
export default {
beforeCreate() {
console.log('我是mixin的beforeCreated')
},
created() {
console.log('我是mixin的created')
},
beforeMount() {
console.log('我是mixin的beforeMount')
},
mounted() {
console.log('我是mixin的mounted')
}
}
// Vue组件
<script>
import mixin from '../mixin'
export default {
mixins: [mixin],
beforeCreate() {
console.log('我是vue组件的beforeCreated')
},
created() {
console.log('我是vue组件的created')
},
beforeMount() {
console.log('我是vue组件的beforeMount')
},
mounted() {
console.log('我是vue组件的mounted')
}
};
</script>
上述代码执行结果为:
我是mixin的beforeCreated
我是vue组件的beforeCreated
我是mixin的created
我是vue组件的created
我是mixin的beforeMount
我是vue组件的beforeMount
我是mixin的mounted
我是vue组件的mounted
- 值为对象的选项键名冲突时,取组件对象的键值对
值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
// minxin.js
export default {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
// Vue组件
<script>
import mixin from '../mixin'
export default {
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
};
</script>
上述代码结果:
foo() => “foo”
bar() => “bar”
conflicting() => “from self”
props,data,mixin中的数据优先级谁最高?
props中的数据,data中的数据,mixin中的数据,
如果出现同名的情况下: props中的优先级最高 data中的其次。但是如果mixin中有生命周期这种特殊的函数和组件中的同名生命周期函数发生冲突了:两个都运行。
plugin 插件
plugin功能:
用于增强 vue
第二个以后的参数是插件使用者
plugin本质:
包含 install 方法的一个对象, install 的第一个参数是 Vue,
传递的数据
plugin使用插件:
Vue.use()
plugin应用场景:
vue cli插件plugins中的方法均可以被任意组件调用,增强Vue的功能。
首先在创建好的vue项目的src目录下新建plugins.js:
export default {
install(Vue) {
// 全局过滤器
Vue.filter('mySlice', function(value){
return value.slice(0, 4);
});
// 自定义指令
Vue.directive('fbind', {
bind(el, binding, vnode) {
el.value = binding.value;
},
inserted(el) {
el.focus();
},
update(el, binding) {
el.value = binding.value;
}
});
// Vue构造函数原型上添加方法
Vue.prototype.hello = ()=>{
console.log('hello');
}
}
}
在main.js中引入plugins,并使用Vue.use应用插件:
import Vue from ‘vue’
import App from ‘./App’
import plugins from ‘./plugins’
Vue.config.productionTip = false
Vue.use(plugins)
new Vue({
el: ‘#app’,
render: h => h(App)
})
School.vue组件中使用插件plugins中的方法:
<template>
<div>
<p>学校名称:{{name | mySlice}}</p>
<p @click="test">学校地址:{{address}}</p>
<input type="text" name="" v-fbind.value="name">
</div>
</template>
<script>
export default {
name: 'School',
data() {
return {
message: 'hello world',
name: 'zz@#1234',
address: 'bj'
}
},
methods: {
test() {
this.hello()
}
}
}
</script>
<style>
</style>
scoped 样式
scoped作用:
让样式在局部生效,防止冲突
scoped写法:
<style scoped>
vue 中的 webpack 并没有安装最新版,导致有些插件也不能默认安装最新版,如
npm i less-loader@7,而不是最新版
为什么要用scoped?
当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,
通过该属性,可以使得组件之间的样式不互相污染。注意:实际开发中,建议在每个组件的 style 身上都加上 scoped 属性。
scoped的原理
为组件实例生成一个唯一标识,给组件中的每个标签对应的dom元素添加一个标签属性:data-v-xxxx
给<style scoped>
中的每个选择器的最后一个选择器添加一个属性选择器,原选择器[data-v-xxxx],
如:原选择器 为:
.container #id div,
则更改后选择器为:
.container #id div[data-v-xxxx]