vue3从0开始实战——基础知识点

首先贴一下vue3 官网的地址 https://v3.cn.vuejs.org/guide/introduction.html#vue-js-%E6%98%AF%E4%BB%80%E4%B9%88

写过vue2项目的都知道我们是如何写代码,但是可能很多人第一次用vue3开发的时候难免会一头雾水,想着要怎么写呢?

其实在vue3里面用vue2的写法也是可以的,不过就是会报很多警告,项目还是可以运行的,不过不建议这么干,不然规范就毫无意义了。

上一篇我们创建了一个新项目,然后我们会发现里面的写法其实和我们vue2差不多,先来看看我们常用的几个吧

一、模板语法

1、插值

vue2vue3 没有什么区别,一样是{{...}}来实现文本插值
父组件:
在这里插入图片描述
子组件:

在这里插入图片描述
效果:
在这里插入图片描述

2、属性

<div class="hello" v-bind:id="helloId">
    <h1>{{ msg }}</h1>
  </div>

和vue2一样,绑定标签属性的时候使用v-bind:,比如常用的 :class,:style;等

3、双向数据绑定 v-model

v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值

我们绑定v-model的时候一般都是直接:value:disabled:checked等,这个提一下,在项目中遇到写到开关查询的时候,我采用了这样的方式v-model:checked="isUsed",猜一猜会发生什么事情?

当我需要这个开关在我做完某些操作之后才去进行状态变更,比如说@change事件或者@click事件之后,然后上述写法就会出现不受代码控制。

比如:isUsed 初始值为false,点击开关之后我需要它依旧是关闭的,执行之后会发现isUsedtrue,开关是开启状态

changeFun(){
	isUsed = false
}

但是直接这么写 :checked="isUsed"isUsed的值就会受代码影响,仍旧为false
所以vue3提供了两种方式,一种是直接响应式不受外界控制的,一种是可中断响应式的方式,所以在开发的时候需要注意。

4、v-if 和 v-for

和vue2写法一样,vue2怎么写、vue3就怎么写

二、组件

1、组件注册

我们开发很多中大型项目的时候,会经常遇到一些功能重复或者覆盖或者耦合的场景,于是我们会封装公共组件来减少代码的冗余,很多时候会注册全局组件。

vue2项目 components公共组件文件目录

在这里插入图片描述
该文件目录下的根文件 index.js

import Vue from 'vue'
const componentList = require.context('.', true, /index.vue/)

const hyphenate = (name) => {
  return name.replace(/\B([A-Z])/g, '-$1').toLowerCase()
}

componentList.keys().forEach(item => {
  const componentItem = componentList(item).default
  Vue.component(hyphenate(componentItem.name), componentItem)
})

上述代码获取 components文件目录下我们封装的组件文件目录名称,然后Vue.component(...)进行组件注册

vue3项目中我们同样可以注册全局组件,方式和vue2有所不同,采用下面的方式

Vue.createApp({...}).component('my-component-name', {
  // ... 选项 ...
})

上述的代码仅仅把 Vue.component(hyphenate(componentItem.name), componentItem) 替换成 Vue.createApp({...}).component(hyphenate(componentItem.name), componentItem)就可以了

2、props

以往vue2的项目开发中你一定知道props的一些传值方式了,来巩固一下

1、静态传值
<HelloWorld msg="Welcome to Your Vue.js App"/>
2、通过 v-bind 或简写 : 动态赋值

变量值 <HelloWorld :msg="msg"/>

表达式值 <HelloWorld :msg="data.msg + data.id"/>

传数字 <HelloWorld :msg="5"/>

传布尔值 <HelloWorld :msg="true"/>,值得注意的是 <HelloWorld is-msg/>这样的写法需要在props里面设置该参数的类型为布尔值,否则拿到的将会是一个字符串

传对象 <HelloWorld :data="{id:1,title:'11111111111'}"/>
单个对象传值 <HelloWorld :id="data.id"/>
将一个对象的所有 property 都作为 prop 传入 给定对象

data: {
	id:1,
	title:'111111'
}

传值 `<HelloWorld v-bind='data'/>` 
等同于 `<HelloWorld :id='data.id' :title='data.title'/>` 

注意:prop是一个单项数据流,是父子之间一个单向下行的数据绑定。每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。

在这里插入图片描述

3、类型检查

我们都知道props接受参数的时候是可以定义该参数类型的,比如官方文档有列出来,借用一下

props: {
    // 基础的类型检查 (`null``undefined` 值会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组的默认值必须从一个工厂函数返回
      default() {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator(value) {
        // 这个值必须与下列字符串中的其中一个相匹配
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组的默认值不同,这不是一个工厂函数——这是一个用作默认值的函数
      default() {
        return 'Default function'
      }
    }
  }

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。vue3和vue2中一样,拿到的参数是可以直接进行绑定在视图上的。

3、插槽

这个东西吧是个好东西,一定要想方设法在工作中用起来,因为它值得。

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。

举个例子:
比如说我们引入一个组件

<slot-bar>添加新的内容</slot-bar>

然而我们slotbar这个组件里面呢是这样的

<div>
	<slot></slot>
</div>

当组件渲染的时候 <slot></slot>就会被‘添加新的内容’直接替换,当然除了字符串之外,插槽还可以渲染html代码,具体用法参考官网https://v3.cn.vuejs.org/guide/component-slots.html#%E6%8F%92%E6%A7%BD%E5%86%85%E5%AE%B9

三、 组合式API

1、vue2代码结构

当我们在vue2中实现一个是组件的时候,往往可能需要如下的代码,每个对应的模块都有他们自己应该做的事情,但是往往有些时候业务复杂,会导致代码很庞大,不利于阅读和理解,二次开发也十分不利

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: { 
      type: String,
      required: true
    }
  },
  data () {
    return {
      repositories: [], // 1
      filters: { ... }, // 3
      searchQuery: '' // 2
    }
  },
  computed: {
    filteredRepositories () { ... }, // 3
    repositoriesMatchingSearchQuery () { ... }, // 2
  },
  watch: {
    user: 'getUserRepositories' // 1
  },
  methods: {
    getUserRepositories () {
      // 使用 `this.user` 获取用户仓库
    }, // 1
    updateFilters () { ... }, // 3
  },
  mounted () {
    this.getUserRepositories() // 1
  }
}

有过vue2开发经验的都非常清楚,结构很碎片化,一个功能我们需要阅读并且理解的话可以需要跳转好几个模块,这样阅读起来是很麻烦的。

于是,vue3给我们提供了组合式API来解决这个问题,也就是setup

2、vue3中的setup

注意:在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。

3、vue3代码结构

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup(props) {
    console.log(props) // { user: '' }

    return {} // 这里返回的任何内容都可以用于组件的其余部分
  }
  // 组件的“其余部分”
}

我们以往在data中声明的对象可以再setup中声明,我们在methods中写的function可以在setup中编写,包括我们vue2中的mounted、computed、watch我们都是写在setup中的。

4、vue2和vue3的区别

以往我们vue2开发项目的时候,按照1中的代码结构,对应的钩子写对应的代码就可以了,但是vue3中不太一样,vue3为了避免我这样的懒癌患者偷懒写代码,于是提供了按需引入,接下来我们就看看我们在vue2开发过程中常用的一些方法在vue3中是如何实现的

1)带 ref 的响应式变量

我们如果要用到ref 必须先引入,不然控制台就会报错,defineComponent主要是针对ts的写法,使用jsx写的话可以不需要

<script>
import { ref } from "vue";
export default defineComponent({
  
});
</script>

引入之后我们便可以声明一个变量,我们对比一下vue2和vue3的区别

vue2:

export default {
  data () {
    return {
      count: 1
    }
  },
  mounted () {
    console.log(this.count) // 1
  }
}

vue3

<script>
import { ref } from "vue";
export default defineComponent({
  setup(props, { emit }) {
  const count = ref(1)
  console.log(count)
  },
});
</script>

你会发现vue2中打印出来的count值为1,但是vue3中不是,vue3打印出来的结果如下
在这里插入图片描述
要获取到count的值,应该是console.log(count.value)
在这里插入图片描述
上述提到过setup里面访问this是访问不到的,所以我们数据绑定count到视图,我们需要将定义的参数return出去

<script>
import { ref } from "vue";
export default defineComponent({
  setup(props, { emit }) {
  const count = ref(1)
  console.log(count)
  return {
     count
  };
  },
});
</script>

除此之外,ref还可以这么用,ref就是用来创建响应式的

<script>
import { ref } from "vue";
export default defineComponent({
  setup(props, { emit }) {
  const count = ref(1)
  const arrayList= ref([])
  const flag= ref(false)
  const title= ref('111111111111')
  return {
     count
  };
  },
});
</script>

综上:所有的用ref所创建的响应式变量都需要.value才能获取到值,改变值,比如count的值改成2,应该是count.value = 2

2)创建响应式对象 reactive

在vue3中要创建json对象的话只能用reactive,不能用ref,比如我们的查询参数

// 查询参数
    const params = reactive({
      page: 1,
      pageSize: 10
    });

同样的我们要使用的时候,要return出去

<script>
import { ref ,reactive} from "vue";
export default defineComponent({
  setup(props, { emit }) {
  const count = ref(1)
  const arrayList= ref([])
  const flag= ref(false)
  const title= ref('111111111111')
  const params = reactive({
      page: 1,
      pageSize: 10
    });
  return {
     count,
     params 
  };
  },
});
</script>

reactive创建的响应式json对象的参数不需要.value去获取值和改变值,可以直接使用 params.page = 1

而在vue2中我们是如此:

export default {
  data () {
    return {
      count: 1,
      params:{
	      page:1,
	      pagesize:10
      }
    }
  },
  mounted () {
    console.log(this.params.page) // 1
  }
}
3)toRefs

当你的数据不需要重新解构的话,一般情况用不上这个,按照正常的符合规范的开发逻辑,这个用处不大,但是具体业务场景需要用到的话,了解这个是解构方法就可以了

4)setup注册声明周期钩子
methods

vue2:

export default {
  data () {
    return {
      count: 1,
      params:{
	      page:1,
	      pagesize:10
      }
    }
  },
  methods:{
    getList(){
    	//通过接口获取列表数据
    }
  }
}

vue3

<script>
import { reactive,onMounted,computed,watch} from "vue";
export default defineComponent({
  setup() {
	  const params = reactive({
	      page: 1,
	      pageSize: 10
	    });
    //通过接口获取列表数据
    funtion getList(){
   	}
	  return {
	     count,
	     params,
	     getList
	  };
  },
});
</script>
mounted

vue2:

export default {
  data () {
    return {
      count: 1,
      params:{
	      page:1,
	      pagesize:10
      }
    }
  },
  mounted(){
  	this.getList()
  },
  methods:{
    getList(){
    	//通过接口获取列表数据
    }
  }
}

vue3:

<script>
import { reactive,onMounted,computed,watch} from "vue";
export default defineComponent({
  setup() {
	  const params = reactive({
	      page: 1,
	      pageSize: 10
	    });
    //通过接口获取列表数据
    funtion getList(){
   	}
   	const mountedFun = onMounted(() => {
      getList();
    });
	  return {
	     count,
	     params,
	     getList,
	     mountedFun 
	  };
  },
});
</script>

注意:vue3中直接使用onMounted替换掉了vue2中的mounted

computed*

vue2:

export default {
  data () {
    return {
      count: 1,
      params:{
	      page:1,
	      pagesize:10
      }
    }
  },
  computed:{
  	pagination(){
  		return  this.params
  	}
  },
  methods:{
    getList(){
    	//通过接口获取列表数据
    }
  }
}

vue3:

<script>
import { reactive,onMounted,computed,watch} from "vue";
export default defineComponent({
  setup() {
	  const params = reactive({
	      page: 1,
	      pageSize: 10
	    });
	   // 分页参数
    const pagination = computed(() => ({
      total: total.value,
      current: params.page,
      pageSize: params.pageSize
    }));
    //通过接口获取列表数据
    funtion getList(){
   	}
   	const mountedFun = onMounted(() => {
      getList();
    });
	  return {
	     count,
	     params,
	     getList,
	     mountedFun,
	     pagination
	  };
  },
});
</script>
watch

vue2:

export default {
  data () {
    return {
      count: 1,
      params:{
	      page:1,
	      pagesize:10
      }
    }
  },
  computed:{
  	pagination(){
  		return  this.params
  	}
  },
  watch:{
  	page(nval){
  	
  	}
  },
  methods:{
    getList(){
    	//通过接口获取列表数据
    }
  }
}

vue3:

<script>
import { reactive,onMounted,computed,watch} from "vue";
export default defineComponent({
  setup() {
	  const params = reactive({
	      page: 1,
	      pageSize: 10
	    });
	   // 分页参数
    const pagination = computed(() => ({
      total: total.value,
      current: params.page,
      pageSize: params.pageSize
    }));
    //通过接口获取列表数据
    funtion getList(){
   	}
   	const mountedFun = onMounted(() => {
      getList();
    });
    watch(
      () => params.page,
      (newValue) => {
        // params.page ++  例子
      }
    );
	  return {
	     count,
	     params,
	     getList,
	     mountedFun,
	     pagination
	  };
  },
});
</script>

综上我们可以看到,在vue3中我们在setup中声明的变量也好,定义的方法也好,都是需要return的,不然控制台就会报警,导致意想不到的结果。

如果本文章让你不是很清晰,可以看官网https://v3.cn.vuejs.org/guide/composition-api-setup.html#%E5%8F%82%E6%95%B0

5、setup

使用 setup 函数时,它将接收两个参数:props,context

1)props

props是响应式的,当传入新的prop` 时,它将被更新。

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

在这里插入图片描述
如果有特定的业务场景需要解构props的话,你需要上面我们提到的torefs

import { toRefs } from 'vue'

setup(props) {
  const { title } = toRefs(props)
  console.log(title.value)
}

如果 title 是可选的 prop,传入的 props 中没有 title ,toRefs 将不会为 title 创建一个 ref ,你需要使用 toRef

import { toRef } from 'vue'
setup(props) {
  const title = toRef(props, 'title')
  console.log(title.value)
}
2)context

context 是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值

export default {
  setup(props, context) {
    // Attribute (非响应式对象,等同于 $attrs)
    console.log(context.attrs)

    // 插槽 (非响应式对象,等同于 $slots)
    console.log(context.slots)

    // 触发事件 (方法,等同于 $emit)
    console.log(context.emit)

    // 暴露公共 property (函数)
    console.log(context.expose)
  }
}

你也可以这么写

export default {
  setup(props, { attrs, slots, emit, expose }) {
    
  }
}

四、vue3的生命周期钩子

在这里插入图片描述

五、总结

罗列一下基础知识点之后,我们会明显的发现vue3其实比vue2的碎片化更利于我们编写代码,避免错误,以及方便阅读和修改。

暂时写这么多,后续会持续更新的。

此文章可能会有不足,只是项目开发的一些记录,如果有什么错误,欢迎指出,我会及时更正。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左撇子没秃头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值