美文网首页Vue.jsvue前端开发那些事儿
Vue3组件(一)做个组件尝尝鲜

Vue3组件(一)做个组件尝尝鲜

作者: 自然框架 | 来源:发表于2021-02-07 17:10 被阅读0次

    .vue文件的分类

    在工程化项目里面,默认会设置views和components这两个文件夹,而两个文件夹里面放的又都是.vue文件,既然是同类型的文件,为啥要设置两个文件夹呢?因为用途有点区别。

    按照使用方式,.vue文件可以分为页面、组件和控件三类。

    页面

    一般存放在views目录里面,一开始我还以为这里的.vue文件不需要属性(props)呢,因为没有谁能给他传递属性值。
    后来学习路由知识后发现我错了,路由不仅可以加载组件,而且还能给组件传递属性。

    这样.vue文件不管在哪,都可以有属性(props),那么从代码角度,就没有明确的区分了。

    所以只能从使用方式来区分一下。

    页面可以看做是路由直接加载的组件,作为一个“容器”,存放多个组件,确定其位置,负责各个组件之间的连系。

    组件

    导航、header、footer这类多个页面共用的部分,或者功能比较独立的部分。
    从页面里面分离出来,可以让代码更清晰易读,扩展性和维护性也会更好。
    比如我要改个导航,直接去找导航组件就好,不用怕误改了其他代码。

    其他组件里面也不会看到共用组件里的代码,指定位置就好。可以把重点放在自己的逻辑上面来。

    控件

    简单的说,就是UI库提供的各种控件,比如表单里的文本框、选择列表框、日期选择控件等,还有表单控件、列表控件、分页控件等。

    虽然在vue里面,这些都是组件的形式出现,但是还是可以细分、明确一下,这样不容易产生误解。

    本系列主要说的是控件这一类的组件。

    我们先用一个简单的文本框来举个例子。

    定义组件

     <template>
      <input
        :value="modelValue"
        @input="myInput"
      ><br>
      组件内部值:{{modelValue}}
    </template>
    
    <script>
    import { toRef, toRefs, watch } from 'vue'
    
    export default {
      name: 'mytext',
      props: {
        modelValue: String,
        meta: Object
      },
      emits: ['input'],
      setup (props, context) {
        // 向父组件提交修改属性
        const myInput = (e) => {
          console.log(e)
          context.emit('update:modelValue', e.target.value)
        }
    
        return {
          myInput
        }
      }
    }
    </script>
    
    • template:模板部分,写html代码和vue的绑定语句。
    • script:js脚本部分。
    • style:可以写css。
    • export default:返回一个对象,用于创建组件。
    • name :组件名称,可以不写这个属性,但是如果要写的话,就不要重名。
    • props:定义组件的属性。
    • emits:定义组件的事件。
    • setup:vue3的新写法。虽然vue3也兼容vue2的方式,但是我们都用上vue3了,那么尽量用新的方式。

    父组件里面使用组件

    <template>
      <div class="home">
        父组件的值:{{value}}<br>
        自己的组件:<mytext v-model="value"/><br>
        原生文本框:<input type="text" v-model="value"/>
      </div>
    </template>
    
    <script>
    import { ref } from 'vue'
    import mytext from '@/components/nf-html/input-text2.vue'
    
    export default {
      name: 'eleBase',
      components: {
        mytext
      },
      setup () {
        const value = ref('1')
    
        return {
          value
        }
      }
    }
    </script>
    
    • import
      可以用 import 的方式引入组件。

    • components
      如果组件没有做全局注册的话,那么需要使用 components 在父组件里面注册。

    setup 的参数

    setup提供两个参数,一个是props,传递组件的属性;一个是context(上下文),提供emit这类的方法。

    props

    在 setup 里面可以通过 props 访问组件的属性,但是请注意:原则上是不允许在组件内部直接修改属性值的。所以一般可以使用 watch 的方式来监控属性的变化。
    但是如果我就是想访问属性呢,结果会如何?
    我们可以设计几个方式来看看效果:

        const myProps1 = props // 获取属性
        const myProps = toRefs(props) // toRefs的方式获取属性
        const myValue = toRef(props, 'modelValue') // toRef获取指定的属性
        console.log('原生属性:', props)
        console.log('toRefs的属性:', myProps)
        console.log('toRef 的属性:', myValue)
        console.log('myProps.modelValue:', myProps.modelValue)
    
        // 直接修改,会报错(ESLint)
        // props.modelValue = '直接改属性'
    
        // 尝试修改,虽然只有警告不会报错,但是修改不会成功。
        myProps1.modelValue = '内部直接修改'
    
        // 尝试修改,虽然只有警告不会报错,但是修改不会成功。
        myValue.value = '内部修改属性'
    
        // 监控属性变化
        watch(() => props.modelValue, (v1, v2) => {
          console.log('原值:', v1)
          console.log('新值:', v2)
        })
    
    • 属性的打印结果


      002setup-propsKind.png

      从打印结果可以看出来,组件的属性被封装成了reactive的形式,然后又在外面套上了readonly,所以实现了无法直接赋值的效果。

    注意:不能修改只是对简单类型有效,如果属性是对象类型的话,还是可以直接修改属性值的。

    • 尝试直接赋值。
      以前尝试直接赋值的时候会报错,现在虽然不报错了,但是无法修改,而且会给出警告,如图:


      002setup-props1.png
    • toRefs 和 toRef


      003setup-propsTorefs.png

    toRefs可以把属性拆分成多个ref的形式,尝试了一下,如果属性是简单类型,还是不可以直接修改值的。但是如果属性类型是对象的话,又可以直接修改值了。

    toRef也是一样的效果。

    context

    我们来看一看context的打印结果:


    001setup-context.png

    比较常用的就是emit,相当于vue2的this.emit。

    我们可以写一个向父组件提交属性的函数

       // 向父组件提交修改属性
        const myInput = (e) => {
          console.log(e)
          context.emit('update:modelValue', e.target.value)
        }
    
    • update:modelValue
      这是修改父组件的属性的一种方法,后面是要修改的值。

    v-model

    vue3支持多个v-model了。父组件可以这样写:

    v-model:foo="foo" v-model:fo="fo" 
    

    如果只需要一个属性的话,也可以简写

    v-model="fooo"
    

    只是组件内部的属性名称要写成固定的“modelValue”,如果是其他属性名称的话,必须用带冒号的方式。

    小结

    这个只是一个开篇,介绍基础知识,后面还有更精彩的内容。

    源码:

    https://github.com/naturefwvue/nf-vue-element

    相关文章

      网友评论

        本文标题:Vue3组件(一)做个组件尝尝鲜

        本文链接:https://www.haomeiwen.com/subject/guymtltx.html