vue.js

vue3项目:npm init vue@latest

vite.config.js-项目的配置文件 基于vite的配置
package.json-项目包文件 核心依赖项变成了vue3.x和vite
main.js-入口文件 createApp函数创建应用实例
app.vue-跟组件 SFC单文件组件 script-template-style
setup选项的执行时机:beforeCreate钩子之前,自动执行
setup写代码的特点是什么:定义数据+函数 然后以对象方式return
<script setup>解决了什么问题:经过语法糖的封装更简单的使用组合API
setup中的this还指向组件的实例吗:指向undefined
reactive():作用:接收对象类型数据的参数传入并返回一个响应式的对象
ref():作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象

<script setup>
  // //1.导入函数
  // import {reactive} from 'vue'
  // //2.执行函数传入一个对象类型的参数 变量接收
  // const state = reactive ({
  //   count:0
  // })
  // const setCount = () => {
  //   state.count++
  // }
  //1.导入ref函数
  import {ref} from 'vue'
  //2.执行函数 传入参数[简单类型+对象类型] 变量接收
  const count = ref(0)
  const setCount =()=>{
    //脚本区域修改ref产生的响应式对象数据 必须通过.value属性
    count.value++
  } 
</script>
<template>
  <div>
    <button @click="setCount">{{ state.count }}</button>
  </div>
</template>

使用ref时button里面直接写count
reactive和ref函数的共同作用:用函数调用的方式生成响应式数据
reactive vs ref:reactive不能处理简单类型的数据;ref参数类型支持更好但是必须通过.value访问修改;ref函数的内部实现依赖于reactive函数

computed函数:

<script setup>
  import {ref} from 'vue'
  import { computed } from 'vue';
  const list = ref([1,2,3,4,5,6,7,8])
  const computedlist = computed (() =>{
    return list.value.filter(item=>item>2)
  })
</script>
<template>
  <div>
    原始响应式数据-{{ list }}
  </div>
  <div>
    计算属性数值-{{ computedlist }}
  </div>
</template>

计算属性只去计算;避免直接修改计算属性的值。
watch函数:侦听一个或者多个数据的变化,数据变化时执行回调函数。immediate(立即执行),deep(深度侦听)

<script setup>
  import {ref, watch} from 'vue'
  const count = ref(0)
  const setCount =() => {
    count.value++
  }
  watch(count,(newVal,oldVal)=>{
    console.log('count变化了',newVal,oldVal)
  })
</script>
<template>
  <div>
    <button @click="setCount">+{{ count }}</button>
  </div>
</template>
<script setup>
  import {ref, watch} from 'vue'
  const count = ref(0)
  const name = ref('cp')
  const changeCount = () =>{
    count.value++
  }
  const changeName = () =>{
    name.value='pc'
  }
  watch([count,name],([newCount,newName],[oldCount,oldName])=>{
    console.log('count或者name改变了',[newCount,newName],[oldCount,oldName])
  })
</script>
<template>
  <div>
    <button @click="changeCount">count改变了--{{ count }}</button>
  </div>
  <div>
    <button @click="changeName">name改变了--{{ name }}</button>
  </div>
</template>
<script setup>
  import { ref, watch } from 'vue';
  const count = ref(0)
  const setCount = () =>{
    count.value++
  }
  watch(count,()=>{
    console.log('count改变了');
  },{
    immediate:true
  })
</script>
<template>
  <div>
    <button @click="setCount">{{ count }}</button>
  </div>
</template>
<script setup>
  import { ref, watch } from 'vue';
  const state = ref({count:0})
  const changeStateByCount = () =>{
    state.value.count++
  }
  watch(state,()=>{
    console.log('count改变了')
  },{
    deep:true
  })
</script>
<template>
  <div>
    <button @click="changeStateByCount">{{ state }}</button>
  </div>
</template>

精确监听:

<script setup>
  import { ref, watch } from 'vue';
  const count = ref({
    name:'zhangsan',
    age:18
  })
  const changeName = () =>{
    count.value.name = 'lisi'
  }
  const changeAge = () => {
    count.value.age = 20
  }
  watch(
    ()=>count.value.name,
    ()=>count.value.age
  )
</script>
<template>
  <div>
    <button @click="changeName">{{ count.name }}</button>
  </div>
  <div>
    <button @click="changeAge">{{ count.age }}</button>
  </div>
</template>

作为watch函数的第一个参数,ref对象需要添加.value吗?不需要,watch会自动读取
watch可以监听单个或多个数据
不开启deep,不能直接修改嵌套属性触发回调
不开启deep,想在某个层次比较深的属性变化执行回调,可以把第一个参数写成函数的写法,返回要监听的具体属性。
组合式API中生命周期函数的格式:on+生命周期名字
组合式API中组件卸载完毕时执行onUnmounted函数

父传子:

<script setup>
  //setup语法糖下局部组件无需注册直接可以使用
  import SonCom from './son-com.vue'

</script>
<template>
  <div class="father">
    <h2>父组件App</h2>
    <!--1.绑定属性-->
    <SonCom message="father message"/>
  </div>
</template>
<script setup>
    
    //2.defineProps接收数据
    defineProps({
        message:String
    })
</script>
<template>
    <div class="son">
        <h3>子组件Son</h3>
        <div>
            父组件传入的数据-{{ message }}
        </div>
    </div>
</template>
响应式数据:
<script setup>
  //setup语法糖下局部组件无需注册直接可以使用
  import SonCom from './son-com.vue'
  import { ref } from 'vue';
  const count = ref(100)
</script>
<template>
  <div class="father">
    <h2>父组件App</h2>
    <!--1.绑定属性-->
    <SonCom :count="count" message="father message"/>
  </div>
</template>
<script setup>
    
    //2.defineProps接收数据
    defineProps({
        message:String,
        count:Number
    })
</script>
<template>
    <div class="son">
        <h3>子组件Son</h3>
        <div>
            父组件传入的数据-{{ message }}-{{ count }}
        </div>
    </div>
</template>

子传父:

<script setup>
 import SonCom from './son-com.vue'
 const getMessage = (msg)=> {
  console.log(msg)
 }
</script>
<template>
  <div class="father">
    <h2>父组件App</h2>
    <!--绑定事件-->
    <SonCom @get-message="getMessage"/>
  </div>
</template>
<script setup>
   const emit = defineEmits(['get-message']) 
   const sendMsg = () => {
    emit('get-message','this is a son message')
   }
   
</script>
<template>
   <div class="son">
    <h3>子组件Son</h3>
    <button   @click="sendMsg">触发自定义事件</button>
   </div> 
</template>
<script setup>
 import { onMounted, ref } from 'vue';
 import TestCom from './test-com.vue'
 const h1Ref = ref(null)
 const comRef = ref(null)
 onMounted(()=>{
  console.log(h1Ref.value)
  console.log(comRef.value)
 })
</script>
<template>
  <h1 ref="h1Ref">我是dom标签h1</h1>
  <TestCom ref="comRef"/>
</template>
<script>
    import { ref } from 'vue';
    import { defineExpose } from 'vue';
    const name = ref('test name')
    const setName = () => {
        name.value = 'test new name'
    }
    defineExpose({
        name,
        setName
    })
</script>
<template>
    <div>我是test组件</div>
</template>

获取模板引用的时机:组件挂在完毕
defineExpose编译宏的作用:显式暴露组件内部的属性和方法
实现跨层传递普通数据:顶层组件通过provide函数提供数据;底层组件通过inject函数获取数据

<script setup>
    import { provide } from 'vue';
    import RoomMsgItem from './room-msg-item.vue'
    import { ref } from 'vue';
    import roomMsgComment from './room-msg-comment.vue';
    provide('data-key','this is room data')
    const count = ref(0)
    provide('count-key',count)
    setTimeout(()=>{
      count.value=100
    },3000)
    const setCount = () =>{
      count.value++
    }
    provide('setCount-key',setCount)
</script>
<template>
    <div class="page">
        顶层组件
        <RoomMsgItem/>
        <roomMsgComment/>
    </div>
</template>
<script setup>

</script>
<template>
 <div class="item">
    中间组件
 </div>
</template>
<script setup>
    import { inject } from 'vue';

    const roomDate = inject('data-key')
    const countData =  inject('count-key')
    const setCountDate = inject('setCount-key')
</script>
<template>
    <div class="comment">
        底层组件
        <div>
            来自顶层组件中的数据为:{{ roomDate }}
        </div>
        <div>
            来自顶层组件的响应式数据为:{{ countData }}
        </div>
        <div>
            <button @click="setCountDate">修改顶层组件的count</button>
        </div>
    </div>
</template>

provide和inject的作用是:跨层组件通信
如何在传递的过程中保持数据响应式:第二个参数传递ref对象
底层组件想要通知顶层组件做修改,需要传递方法,底层组件调用方法
一颗组件树可以存在多个顶层和底层的关系
列表渲染||删除功能||编辑功能

<script setup>
import Edit from './components/Edit.vue'
import {ref,onMounted} from 'vue'
import axios from 'axios';

// TODO: 列表渲染
//思路:声明响应式list -> 调用接口获取数据 -> 后端数据赋值给list -> 绑定到table组件
const list = ref([])
const getList = async () => {
  //调用接口
  const res = await axios.get('/list')
  //赋值给list
  list.value = res.data
}
onMounted(()=>getList())
// TODO: 删除功能
//思路:获取当前行的id -> 通过id调用删除接口 -> 更新最新的列表
const onDelete = async (id) => {
  console.log(id)
  await axios.delete(`/del/${id}`)
  getList()
}

// TODO: 编辑功能
//打开弹窗 -> 回填数据 -> 更新数据
//1.打开弹窗(获取子组件实例 调用方法或者修改属性)(需要用到组件edit.vue,将弹窗开关改为true,但是需要在父组件中使用)
//2.回填数据(调用详情接口/当前行的静态数据)(调用open方法的同时直接将数据传下来)
const editRef = ref(null)//获取子组件的属性,用到ref标识
const onEdit = (row) => {
  editRef.value.open(row)
}
</script>

<template>
  <div class="app">
    <el-table :data="list">
      <el-table-column label="ID" prop="id"></el-table-column>
      <el-table-column label="姓名" prop="name" width="150"></el-table-column>
      <el-table-column label="籍贯" prop="place"></el-table-column>
      <el-table-column label="操作" width="150">
        <template #default="{row}">
          <el-button type="primary" @click="onEdit(row)" link>编辑</el-button>
          <el-button type="danger" @click="onDelete(row.id)" link>删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
  <Edit ref="editRef" @on-Update="getList"/>
</template>

<style scoped>
.app {
  width: 980px;
  margin: 100px auto 0;
}
</style>
<script setup>
// TODO: 编辑
import { ref } from 'vue'
import axios from 'axios';
// 弹框开关
const dialogVisible = ref(false)
//准备form(利用形参来获取数据)
const form = ref({
  name:'',
  place:'',
  id:''
})
const open = (row) => {//通常使用方法来打开弹窗
  dialogVisible.value = true
  console.log(row)
  form.value.name = row.name
  form.value.place = row.place
  form.value.id = row.id
}
defineExpose({//子传父(抛出)
  open
})
//更新
const emit = defineEmits(['on-Update'])
//1.收集表单数据 调用接口
const onUpdate = async () => {
  await  axios.patch(`/edit/${form.value.id}`, {
    name: form.value.name,
    place: form.value.place,
  })
//2.关闭弹窗
dialogVisible.value = false
//3.通知父组件做列表更新(触发onUpdate函数)
emit('on-Update')
}
</script>

<template>
  <el-dialog v-model="dialogVisible" title="编辑" width="400px">
    <el-form label-width="50px">
      <el-form-item label="姓名">
        <el-input placeholder="请输入姓名" v-model="form.name"/><!--template会自动解包,所以不用写.value-->
      </el-form-item>
      <el-form-item label="籍贯">
        <el-input placeholder="请输入籍贯" v-model="form.place"/>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="onUpdate">确认</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<style scoped>
.el-input {
  width: 290px;
}
</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值