vue学习第2天,基础知识,v-bind v-on v-if v-for v-model v-html computed watch methods

本文介绍Vue.js的基础使用方法,包括创建Vue实例、指令如v-model、v-bind、v-on等的使用,以及计算属性和侦听器的概念。还介绍了如何通过Vue组件自定义模板。

1,还没有开始学习node npm webpack vue-cli等工具

2,使用传统的写页面的方法引入的vue

3,创建vue对象 

var app=new({

el:'#id',

data:{

name:'sukla',

age:2017,

some:'',

value:'',

istrue:true,

isActive:true

todos:[

{text:"sukla1“,date:"2017-10-17"},

{text:"sukla2",date:"2017-10-18"}

]

},

methods:{

computedvalue:function(){

this.value++

},

doSomething:function(){

alert("你还真点啊!")

},

computed:{

computedvalue:function(){

return this.value+1;

},

computedclass1:function(){

return isActive?this.class1:";

}

},


watch:{

value:function(){

value++

}

}

}

})

4,el 是vue实现的一个属性,app.$el===app.el===document.getElementById('id'),表示的是当前页面上面id为 ‘id’的元素;

5,data 是vue实现的一个属性,app.$data===app.data;

6,加$是为了区分自有属性和用户自定义属性;

7,v-model

<input v-model="some"/> 将这个元素的值和对应的vue对象的data中的some属性的值绑定,当修改这个input的值的时候,data中的some属性对应的值也发生改变,可以在多个元素上绑定,当一个发生修改的时候,同时变化;

如果只是想绑定一次的话,可以使用 v-once 

8,v-bind

<input v-bind:name="name"/> 将参数 name="name" 传给v-bind 告诉v-bind 这个元素的name属性的值是data中的name属性对应的值 ,可以动态改变

9,v-on

<a v-on:click="doSomething">点我啊</a> 将参数click="doSomething" 传给v-on 告诉v-on 当这个元素执行click动作的时候 执行methods中的doSomething所对应的方法

10,v-if

<a v-if="istrue">我能藏起来</a>  用来控制这个元素的显示与隐藏 当data中的istrue属性对应的boolean值为true的时候 这个元素就能看见,当为false的时候就看不见了,但是位置还在

11,v-for

<ol><li v-for="todo in todos">{{todo.text}}</li></ol> 一般用来配合插值 循环插一批元素

12,v-html

<div v-html="rawhtml"></div> 指定将data中的rawhtml属性对应的字符串按照html格式解释后插入这个元素里面,注意不能将自定义的模板写在那个字符串里面,引擎解释不出来

13,class

<div v-bind:class="class1"></div> 指定当前元素的class属性中有一个是在data中的class1对应的值

<div v-bind:class="{class2:isActive}"><div> 指定当前元素有一个叫做class2的类在class属性当中,但是受到data中的isActive对应的boolean值的控制,isActive为true的时候加上去,isActive为false的时候就去掉

<div v-bind:class="[class1,class2]"></div> 指定当前元素的class属性中添加数组[class1,class2]中每个值在data中对应的值的class

<div v-bind:class="[{class1:isActive},class2]"></div> 指定当前元素的class属性种添加数组[{class1:isActive},class2]中对应的每一个值在data中的值所表示的class,但是其中的class1是否添加是被data中的isActive对应的boolean值所控制的,为true的时候 添加,为false的时候就不添加

<div v-bind:class="[computedclass1,class2]"></div> 在一个表达式中写太多的东西看上去不够清爽,可以使用计算属性,将计算过程放到其它地方

14,computed 计算属性 里面的this表示的是当前这个Vue对象,这个对象代理了data里面的属性与方法,可以直接 . 调用

15,computed 与 methods 缓存问题

<input v-model="value"/> <div>{{computedvalue}}</div>  <div>{{computedvalue()}}</div>发现用计算属性和方法都可以实现input的输入的值加1之后放到div中,其中计算属性是依赖缓存的,如果缓存没有变化就不去计算了,而方法是只要触发了,不管结果有没有变化都执行下去,如果不希望有缓存的话就使用methods,如果需要有缓存的话就使用计算属性computed

16,watch 当指定的属性的值发生改变的时候 就执行一次watch里面的方法

17,component 模板 可以自定义模板 然后在html上像标签一样使用

Vue.component("component",{

template:"<div>我是一个模板</div>",

porps:[]

})

<component></component>

渲染出来之后 <div>我是一个模板</div>








<think> 我们正在封装el-select组件,并且使用了v-bind绑定属性,包括filterable: true,但是发现filter-method无效。 根据之前的讨论,我们知道自定义指令(如滚动加载)可能会覆盖原生的过滤逻辑,导致filter-method失效。 但是,现在的情况是,我们没有使用自定义指令,而是仅仅通过v-bind绑定属性,包括filterable: true,然后传递filter-method方法。 问题可能在于:在封装组件中,我们使用了v-bind="attrs"来传递属性,但是事件监听器(如filter-method)可能需要单独处理。 解决方案: 1. 确保在封装组件中,除了使用v-bind绑定属性外,还要使用v-on绑定事件监听器。 2. 注意:filter-method实际上是一个prop(属性),但它是一个函数,因此它会被放在$attrs中吗?实际上,在Vue中,函数类型的prop会被放在$attrs中吗?不会,因为prop是显式声明的,不会在$attrs中。但是,如果我们没有在组件的props中声明filter-method,那么它就会被放在$attrs中。 然而,在Element UI中,el-select的filter-method是一个属性(prop),它期望一个函数。所以,我们在封装组件中需要显式声明filter-method这个prop,然后将其传递给el-select。 另外,事件监听器(如@filter-method)?注意:在el-select中,filter-method是一个属性,而不是事件。所以,我们只需要将其作为属性传递即可。 但是,当我们使用v-bind="attrs"时,它会将父组件传递的所有非prop属性绑定到el-select上。由于filter-method在封装组件中没有声明为prop,所以它会被包含在attrs中,从而传递给el-select。 那么为什么无效呢? 可能的原因: 1. 我们可能同时使用了v-bind和v-on,但是filter-method是一个prop,所以应该用v-bind传递,而不是v-on2. 另外,注意在封装组件中,我们可能覆盖了el-select的默认行为。 另一种可能:在使用封装组件时,我们传递了filterable属性以及filter-method方法,但是filterable属性可能是通过v-bind绑定到封装组件的,而封装组件没有将其传递给el-select。 所以,我们需要在封装组件中确保: - 使用v-bind="attrs"传递所有非prop属性(包括filterable和filter-method等) - 使用v-on="listeners"传递所有事件(虽然filter-method不是事件,但是其他事件可能需要传递) 但是,在Vue2中,我们可以使用v-bind="attrs"和v-on="listeners"来分别传递属性和事件。 具体步骤: 1. 在封装组件的el-select上绑定:v-bind="mergedAttrs" (mergedAttrs包含所有父组件传入的非prop属性) 同时,绑定v-on="mergedListeners" (合并的事件监听器) 2. 在组件中,使用props声明我们明确需要接收的属性(比如value、options等),这样这些属性就不会出现在attrs中。 但是,filter-method和filterable我们可能没有在封装组件的props中声明,所以它们会出现在attrs中,然后被传递给el-select。 3. 然而,如果我们在封装组件的props中声明了filterable,那么filterable就不会在attrs中,所以我们需要手动传递。 因此,建议: - 在封装组件中,对于el-select的原生属性(包括filterable、filter-method等),如果我们不打算在封装组件内部使用,就不需要在props中声明,这样它们就会自动进入attrs,然后通过v-bind="attrs"传递给el-select。 - 如果我们在封装组件的props中声明了某些属性,那么我们需要在el-select上显式绑定这些属性,例如::filterable="filterable" 所以,有两种做法: 做法一(推荐):不在封装组件的props中声明这些属性,而是让它们自动进入attrs,然后通过v-bind="attrs"传递。 做法二:在封装组件的props中声明这些属性,然后显式传递到el-select上。 由于我们不确定用户会传递哪些属性给el-select,所以做法一更通用。 示例代码: 封装组件(CustomSelect.vue): <template> <el-select v-bind="$attrs" v-on="$listeners" > <slot></slot> </el-select> </template> <script> export default { // 注意:这里不要声明props,因为我们要把所有的父组件传递的属性(除了props中声明的)都传给el-select?不对,实际上,我们需要在props中声明一些我们确实需要的属性(比如v-model对应的value),否则会有警告。 正确做法: props: { value: {} // 因为我们有v-model }, inheritAttrs: false, // 避免顶层容器绑定属性 created() { // 此时,this.$attrs包含了除value外的所有父组件传递的属性(因为value在props中声明了) } </script> 但是,这样有一个问题:事件监听器?我们使用了v-on="$listeners"来传递所有事件。 注意:filter-method是一个属性,所以它应该通过v-bind传递。而事件,比如@change、@focus等,通过v-on传递。 因此,在封装组件中,我们只需要: <el-select v-bind="$attrs" v-on="$listeners"> <slot></slot> </el-select> 但是,这样会丢失v-model?不会,因为v-model相当于:value和@input,而value在props中声明,所以它不在$attrs中,而@input在$listeners中,所以我们需要在el-select上绑定:value和@input吗? 实际上,我们可以用计算属性来合并: <el-select :value="value" v-bind="attrsWithoutValue" @input="handleInput" v-on="otherListeners"> 这样太麻烦。 所以,更好的做法是使用计算属性来合并属性和事件。 但是,Vue2.4提供了v-bind和v-on的合并写法: 我们可以这样: <el-select :value="value" v-bind="$attrs" v-on="$listeners"> <slot></slot> </el-select> 然后,在props中声明value,这样$attrs中就不会包含value,而$listeners中会包含input事件(因为v-model会传递input事件)。 这样,el-select就会接收父组件传递的filterable和filter-method等属性,以及所有的事件。 但是,注意:el-select的v-model会生效,因为这里我们绑定了:value和v-on="$listeners",而$listeners中包含了input事件,当el-select内部触发input事件时,会触发父组件的input事件,从而更新value。 所以,封装组件的写法: <template> <el-select :value="value" v-bind="$attrs" v-on="listeners"> <slot></slot> </el-select> </template> <script> export default { name: 'CustomSelect', props: { value: [String, Number, Array] // 根据el-select的value类型 }, computed: { listeners() { return { ...this.$listeners, input: (value) => { this.$emit('input', value) } } } } } </script> 但是,这样写input事件被覆盖了,其实我们可以不用覆盖,因为$listeners中已经包含了input事件,所以我们可以直接绑定v-on="$listeners"。 实际上,我们不需要覆盖input事件,直接: <el-select :value="value" v-bind="$attrs" v-on="$listeners"></el-select> 这样,当el-select触发input事件时,会通过$listeners传递到父组件,然后父组件更新v-model绑定的值。 因此,我们只需要这样写封装组件,就可以传递所有的属性和事件,包括filterable和filter-method。 但是,为什么这样写之后filter-method还是无效呢? 可能的原因: 1. 我们可能同时传递了filterable和filter-method,但是filterable没有正确传递?因为filterable是一个布尔值,在封装组件中,我们通过$attrs传递,所以应该没问题。 2. 检查父组件:在使用封装组件时,是否同时设置了filterable和filter-method? 父组件示例: <custom-select v-model="selected" filterable :filter-method="myFilterMethod" > <el-option ... /> </custom-select> 3. 注意:在封装组件中,我们使用了:value="value"来绑定value,而$attrs中可能没有value,所以el-select会接收到value绑定和attrs中的其他属性。 4. 另外,我们使用了v-on="$listeners",所以事件都可以传递。 因此,按照上面的封装,应该可以正常工作。 但是,如果仍然无效,我们可以尝试在封装组件中显式传递filter-method属性: <el-select :value="value" v-bind="$attrs" v-on="$listeners" :filter-method="$attrs.filterMethod" > 这样写是多余的,因为v-bind="$attrs"已经包含了filter-method。 所以,问题可能出现在其他地方? 另一种可能:在封装组件中,我们可能使用了多个el-select,或者有其他的逻辑干扰。 如果我们没有使用自定义指令(如滚动加载),那么按照上面的封装应该是没问题的。 所以,请检查封装组件的代码,确保没有其他干扰逻辑。 总结解决方案: 1. 在封装组件中,使用:value="value"绑定value(v-model的一部分) 2. 使用v-bind="$attrs"传递所有其他属性(包括filterable和filter-method) 3. 使用v-on="$listeners"传递所有事件 4. 在封装组件的props中声明value 代码模板: <template> <el-select :value="value" v-bind="$attrs" v-on="$listeners" > <slot></slot> </el-select> </template> <script> export default { name: 'CustomSelect', props: { value: [String, Number, Array, Boolean, Object] }, inheritAttrs: false // 避免在根元素上绑定属性 } </script> 然后,在父组件中,按照el-select的原生方式使用filterable和filter-method即可。 如果仍然无效,请检查: - 父组件传递的filter-method是否是一个函数?比如:filter-method="myFilter"而不是@filter-method="myFilter"(注意filter-method是属性,不是事件) - 是否在封装组件中遗漏了filterable属性?实际上,在父组件中,filterable是作为属性传递(不需要冒号,因为它是一个布尔值),而filter-method需要冒号(因为是表达式)。 注意:父组件中,如果filterable是动态的,则需要使用:filterable="true",但我们通常直接写filterable。 最后,如果问题仍然存在,请提供一个最小可复现的示例。 相关问题: 1. 封装el-select组件时,如何正确传递事件? 2. 使用v-bind="$attrs"和v-on="$listeners"有什么注意事项? 3. 如何在封装组件中处理v-model? 4. 封装el-select后,为什么某些属性无效? 参考文献: [1] Vue官方文档:将原生事件绑定到组件:https://cn.vuejs.org/v2/guide/components-custom-events.html#%E5%B0%86%E5%8E%9F%E7%94%9F%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E5%88%B0%E7%BB%84%E4%BB%B6 [2] Vue官方文档:非Prop特性:https://cn.vuejs.org/v2/guide/components-props.html#%E9%9D%9E-Prop-%E7%89%B9%E6%80%A7 </think> ### 封装 `el-select` 后 `filter-method` 无效的解决方案 当使用 `v-bind="{ filterable: true }` 绑定属性后 `filter-method` 无效,根本原因是 **属性绑定冲突** 和 **事件传递中断**。以下是具体解决方案: #### 问题原因分析 1. **属性覆盖冲突**:使用 `v-bind="{ filterable: true }` 会覆盖父组件传递的 `filter-method` 属性 2. **事件未透传**:封装组件未正确处理 `filter-method` 事件监听 3. **作用域隔离**:`v-bind` 的对象语法导致原生事件监听失效 --- ### 修复方案代码 #### 封装组件 (`CustomSelect.vue`) ```vue <template> <el-select ref="selectRef" v-model="innerValue" :filterable="mergedFilterable" <!-- 动态绑定 --> v-bind="filteredAttrs" <!-- 过滤后的属性 --> @filter-method="handleFilter" <!-- 事件重定向 --> > <slot></slot> </el-select> </template> <script> export default { props: { value: [String, Number, Array], // 必须声明 value filterable: { type: Boolean, default: undefined }, // 其他 props... }, computed: { // 合并 filterable 属性(优先使用 prop) mergedFilterable() { return this.filterable ?? !!this.$attrs.filterable }, // 过滤不需要重复绑定的属性 filteredAttrs() { const { filterable, ...rest } = this.$attrs return rest } }, data() { return { innerValue: this.value } }, watch: { value(newVal) { this.innerValue = newVal } }, methods: { // 事件重定向方法 handleFilter(query) { if (this.$listeners['filter-method']) { this.$listeners['filter-method'](query) } } } } </script> ``` #### 使用示例 ```vue <template> <custom-select v-model="selectedValue" :filterable="true" <!-- 启用过滤 --> :filter-method="handleFilter" <!-- 绑定方法 --> v-bind="{ placeholder: '搜索...', clearable: true }" > <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" /> </custom-select> </template> <script> export default { methods: { // 自定义过滤逻辑 handleFilter(query) { this.options = this.allOptions.filter(item => item.name.includes(query) ) } } } </script> ``` --- ### 关键修复点 #### 1. 属性合并机制 ```js computed: { mergedFilterable() { // 优先使用显式 prop,其次使用 attrs return this.filterable ?? !!this.$attrs.filterable }, filteredAttrs() { const { filterable, ...rest } = this.$attrs return rest // 排除重复属性 } } ``` #### 2. 事件重定向 ```vue <el-select @filter-method="handleFilter"> ``` ```js methods: { handleFilter(query) { // 透传父组件的事件监听 if (this.$listeners['filter-method']) { this.$listeners['filter-method'](query) } } } ``` #### 3. 正确使用 `v-bind` ```vue <!-- 正确用法 ✅ --> <custom-select :filterable="true" v-bind="{ placeholder: '搜索...' }" > ``` --- ### 属性传递对比表 | 错误用法 | 正确用法 | 问题说明 | |---------|---------|---------| | `v-bind="{ filterable: true }` | `:filterable="true"` | 对象语法会覆盖所有属性 | | 无 `filter-method` 事件处理 | 添加 `@filter-method` 重定向 | 事件监听未透传 | | 未声明 `value` prop | 显式声明 `value` prop | v-model 失效 | --- ### 注意事项 1. **属性优先级**: ```js // 显式 prop > $attrs return this.filterable ?? !!this.$attrs.filterable ``` 2. **禁用继承属性**(可选): ```js export default { inheritAttrs: false, // 避免自动绑定到根元素 // ... } ``` 3. **调试技巧**: ```js mounted() { console.log('当前属性', this.$attrs) console.log('事件监听', this.$listeners) } ``` 4. **动态绑定优化**: ```vue <!-- 动态绑定对象 --> <custom-select v-bind="dynamicAttrs"> ``` --- ### 相关问题 1. 如何解决封装组件时 `v-model` 失效的问题?[^1] 2. 在 Vue 中如何正确合并多个 `v-bind` 对象?[^2] 3. 为什么 `$attrs` 不包含已声明的 props? 4. 封装组件时如何处理 Element UI 的 `remote-method` 属性? 5. 如何避免重复传递属性导致的冲突? 6. Vue 的 `inheritAttrs` 选项有什么作用? > 引用说明:属性合并机制参考 Vue 的属性继承原理[^1],事件处理参考 Vue 的事件传递机制[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值