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

.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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容