NoteZ_技术博客 NoteZ_技术博客
🏠 首页
  • 📚 Web技术
  • 📋 Npm笔记
  • 📑 Markdown
  • 📄 Git笔记
  • 📝 Nginx文档
  • 📓 Linux文档
  • 📖 技术文档
  • 📜 其他文档
  • 🧊 NodeJs
  • 🎡 Express
  • 🔥 Rust
  • 🎉 Koa2
  • 🍃 MongoDB
  • 🐬 MySql
  • 🥦 Oracle
  • 🍁 Python
  • 🍄 JavaScript
  • 🌰 CSS
  • 🧄 HTML
  • 🥑 Canvas
  • 🌽 Nuxt
  • 🍆 React
  • 🥜 Vue
  • 🧅 TypeScript
  • 🌶️ AI
  • 📘 分类
  • 📗 标签
  • 📙 归档
⚜️ 在线编辑 (opens new window)
  • 📁 站点收藏
  • 📦 前端组件库
  • 📊 数据可视化
  • 🌈 开源插件
  • 🎗️ 关于我
  • 🔗 友情链接
GitHub (opens new window)

NoteZ_技术博客

前端界的小学生
🏠 首页
  • 📚 Web技术
  • 📋 Npm笔记
  • 📑 Markdown
  • 📄 Git笔记
  • 📝 Nginx文档
  • 📓 Linux文档
  • 📖 技术文档
  • 📜 其他文档
  • 🧊 NodeJs
  • 🎡 Express
  • 🔥 Rust
  • 🎉 Koa2
  • 🍃 MongoDB
  • 🐬 MySql
  • 🥦 Oracle
  • 🍁 Python
  • 🍄 JavaScript
  • 🌰 CSS
  • 🧄 HTML
  • 🥑 Canvas
  • 🌽 Nuxt
  • 🍆 React
  • 🥜 Vue
  • 🧅 TypeScript
  • 🌶️ AI
  • 📘 分类
  • 📗 标签
  • 📙 归档
⚜️ 在线编辑 (opens new window)
  • 📁 站点收藏
  • 📦 前端组件库
  • 📊 数据可视化
  • 🌈 开源插件
  • 🎗️ 关于我
  • 🔗 友情链接
GitHub (opens new window)
  • JavaScript笔记

  • CSS笔记

  • HTML笔记

  • Canvas笔记

  • Nuxt笔记

  • React笔记

  • Vue笔记

    • markdown(md-editor-v3)简单使用
    • Prop 验证 与 非 Prop 的 Attribute
    • transition-group列表过渡
    • transition过渡&动画
    • vetur 中 eslint 的问题
    • vite 打包时内存溢出处理方案
    • Vite2 + Vue3添加svg的使用并通过svg实现自定义Icon组件
    • Vite项目构建优化之移除console.log和其他生产日志
    • vsCode 之 Monaco Editor 在 vue-cli3.0 中的使用方法
    • vue cli3 中的使用Luckysheet和Luckyexcel
    • vue 与 Koa 上传示例代码
    • vue 中 axios 如何取消请求,取消前面一个或多个请求
    • Vue 中 node-sass 安装失败简单解决方案
    • vue 中使用 pinia 状态管理教程
    • vue 中使用 web worker
    • vue 中封装 Axios 和 管理 API 接口
    • vue 中的 hash 与 history 两种路由模式
    • Vue 中的鼠标事件汇总
    • Vue 实现 Base64 图片上传
    • vue 强制刷新组件
    • Vue 组件中 v-mode 的本质以及实现方式
    • vue 组件中的.native 原生事件(@click.native)
    • Vue 组件中的.native原生事件(@click.native)
    • Vue 页面路由(router)权限控制和登陆验证
    • Vue 项目中如何在打包时清除 console 和 debugger
    • Vue 项目打包去除 .map 文件方法
    • Vue 预渲染之 prerender-spa-plugin 的配置使用
    • vue-cli 2.x和3.x配置移动端适配px自动转为rem
    • vue-cli3 如何实现pc端自适应
    • vue-cli3.0 开启 Gzip 压缩方法
    • Vue-cli3.0 监听路由变化的几种方式
    • Vue-cli3.0 结合 axios 解决生产环境中的跨域问题
    • vue-cli3.0移动端项目将px转换成rem
    • vue-cli3.x项目兼容ie解决方案
    • vue-router传递参数的几种方式
    • Vue2-ace-editor 基本使用方法
    • vue2.x 插槽slot使用总结
    • Vue2.x 组件通信方式
    • vue3 + vite 自适应(rem 适配)方法
    • vue3+vite:本地代理,配置proxy
    • Vue3.0 基础知识点总结
      • 1. vue3.0 环境搭建
        • 1.1. 安装 @vue/cli (将cli升级到4版本)
        • 1.2. 创建项目模板
      • 2. vuex/router/vue 的变化
        • 2.1. vue 初始化时的变化
        • 2.2. vuex 初始化时的变化
        • 2.3. router 初始化时的变化
      • 3. 变量的定义及使用方法
        • 3.1. ref 的使用方法
        • 3.2. reactive 的使用方法
        • 3.3. 之前的ref的使用方法
      • 4. 生命周期函数的使用
      • 5. 路由的使用方法
      • 6. vuex 的使用方法
      • 7. composition 使用方法
      • 8. 关于插件的新思路
      • 9. 新观察者简单使用
      • 10. 新的计算属性使用方法
      • 11. customRef 简单使用(防抖)
      • 12. 组件与注入
    • Vue3.0 挂载方法,添加全局属性
    • vue3.0之全局变量app.config.globalProperties的使用
    • vue3.2+elelmenui-plus+vite 按需导入ui组件库
    • vue3.x 中使用 ol (openlayer)地图
    • Vue3.x 组件通信方式
    • Vue3全局变量的定义和使用
    • Vuex使用记录
    • vue中使用html2canvas将html页面转为图片并且下载该图片
    • vue中父子组件之间的通信
    • Vue中的防抖函数封装和使用
    • Vue中配合clipboard.js实现点击按钮复制内容到剪切板
    • vue使用monaco editor时报错 Unexpected usage at EditorSimpleWorker.loadForeignModule
    • Vue列表渲染之数组、对象更新检测
    • Vue实现下拉滚动加载刷新功能
    • Vue开发中安装库经常报错
    • Vue技术框架
    • Vue生命周期
    • Vue监听store中数据变化的两种方式
    • Vue非父子组件之间通信的几种方式
    • Vue项目 解决 vuex 在页面刷新后数据丢失的问题
    • vue项目nginx部署子目录_vue 多项目部署_二级目录 copy
    • 使用 monaco-editor 汉化 右键菜单汉化
    • 使用 vite 脚手架创建 vue3 项目
    • 使用animate库
    • 使用vue实现鼠标框选文件的功能
    • 使用vue的transition标签结合css样式完成动画
    • 关于Vue项目优化方案总结
    • 关于解决vue-cli2.xx、vue-cli3.xx项目在ie中白屏的方案总结
    • 利用create-nuxt-app脚手架创建NuxtJS应用
    • 国际化插件 vue-i18n 使用方法
    • 在 vite-vue3.x 中的使用 vscode monaco-editor 方法
    • 在 Vue 中 如何使用 jsencrypt 实现 Rsa 进行加密
    • 在 vue 中使用 jsPlumb 总结
    • 在 vue 中使用 v-viewer 预览图方法
    • 在 Vue 中读取本地文本文件(兼容各种浏览器)
    • 在 vue 或 vuex 中如何使用 axios 进行请求操作
    • 在 vue 项目中 mock 的基本使用方法
    • 在 vue-cli3 项目更改 favicon 图标
    • 在 vue-cli3.0 中使用 Sass 全局变量
    • 在vue3+vite中使用markdown(v-md-editor)编辑器
    • 在vue中如何使用watch深度监听对象中值的变化
    • 基于 vue 列表拖拽排序
    • 基于 vue 图片裁剪(vue-cropper)
    • 基于 vue 的 CodeMirror 代码编辑器
    • 如何在 vue 中使用 swiper 插件创建轮播图
    • 如何在 vue 中实现代码高亮?
    • 如何在 Vue-cli3.0 中使用 prerender-spa-plugin 进行预渲染
    • 如何用 vue 实现一个虚拟列表
    • 清除项目中无用的console.log代码方法
    • 解决vue-cli3.0中提示syntax 'classProperties' isn't currently enabled的错误
    • 记录vite打包vue项目内存溢出问题及解决方法
    • Vite中使用 svg-sprite-loader加载svg文件
    • vite引入svg图片
    • vue 使用CompressionPlugin压缩解决打包后文件过大的问题
    • vue2.x递归组件 树形组件
    • vue3.x递归组件 树形组件
    • 使用Vite快速构建Vue3+ts+pinia脚手架
    • 启动vue项目时报错digital envelope routines__unsupported
    • Pinia 快速入门(使用教程)
    • 关于 Vite Vue 辨别当前所处于什么(生产、开发)环境
  • TypeScript笔记

  • AI相关笔记

  • 开发文档
  • Vue笔记
NoteZ
2020-12-12
目录

Vue3.0 基础知识点总结

vue3.0重要的优化点

    1. 模板编译速度的提升, 对静态数据的跳过处理.
    1. 对数组的监控
    1. 对ts有了很好的支持
    1. 对2.x版本的完全兼容
    1. 可以有多个根节点 (也有bug, 比如外层开了display:flex 那么里面会收到影响, 也就是说布局更灵活但也更要小心, 总之请对自己与他人的代码负责)
    1. 支持Source map, 虽然没演示但是这点真的重要

# 1. vue3.0 环境搭建

# 1.1. 安装 @vue/cli (将cli升级到4版本)

npm install -g @vue/cli
1

# 1.2. 创建项目模板

vue create next-test
1

# 2. vuex/router/vue 的变化

# 2.1. vue 初始化时的变化

import { createApp } from 'vue';
import App from './App.vue'
import router from './router'
import store from './store'

// 方法一. 创建实例变成了链式, 直接写下去感觉语义与结构有点模糊, 但是我们要理解vue这样做的良苦用心, 前端趋近于函数化.
// createApp(App).use(router).use(store).mount('#app')

// 方法二.
const app = createApp(App);
app.use(router);
app.use(store);
app.mount('#app');
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.2. vuex 初始化时的变化

import { createStore } from 'vuex'
// 专门创建实例的一个方法
export default createStore({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
});
1
2
3
4
5
6
7
8
9
10
11
12

# 2.3. router 初始化时的变化

import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
]

const router = createRouter({
// 专门创建history的函数
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3. 变量的定义及使用方法

# 3.1. ref 的使用方法

import { ref } from "vue";
export default {
  // 1: 这个版本基本逻辑都在setup里面完成了, 有人说把他当成2.x的data.
  setup() {
    // 2: 定义一个追踪的变量,也就是双向绑定.
    const n = ref(1); // 生成的n是一个对象, 这样方便vue去监控它
    function addN() {
      n.value++; // 注意这里要使用.value的形式, 因为n是对象↑, value才是他的值
    }
    return {
      n,   // 返回出去页面的template才可以使用它, {{n}} 不需要.value
      addN
    }
  }
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.2. reactive 的使用方法

import { reactive, toRefs } from "vue";
export default {
  setup() {
    // 注意事项: reactive的对象不可以结构返回或导入, 会导致失去响应式
    const obj = reactive({
      name: "金毛",
      age: 4
    });
    function addObj() {
      obj.age++;
    }
    return {
      ...obj, // 这样写不好, 里面会失去响应式
      obj, // 这样写那么外面就要都基于obj来调取, 类型{{obj.age}}
      ...toRefs(obj) // 必须是reactive生成的对象, 普通对象不可以, 他把每一项都拿出来包了一下, 我们可以这样用了 {{age}}, 放心咱们多深的obj也可以响应
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.3. 之前的ref的使用方法

<div>
  <div ref="content">第一步, 在dom上面定义, 他会有一个回调</div>
</div>
<ul>
  <li>v-for 出来的ref</li>
  <li>可以写为表达式的形式, 可以推导出vue是如何实现的</li>
  <li>vue2.x的时候v-for不用这么麻烦, 直接写上去会被组装成数组</li>
  <li :ref="el => { items[index] = el }" v-for="(item,index) in 6" :key="item">{{item}}</li>
</ul>
1
2
3
4
5
6
7
8
9
import { ref, onMounted, onBeforeUpdate } from "vue";
export default {
  setup() {
    // 2: 定义一个变量接收dom, 名字无所谓, 但是与dom统一的话会有很好的语义化
    const content = ref(null);
    const items = ref([]);

    // 4: 在生命周期下, 这个值已经完成了变化, 所以当然第一时间就拿到
    onMounted(() => {
      console.log(content.value);
      console.log("li标签组", items.value);
    });

    // 5: 确保在每次变更之前重置引用
    onBeforeUpdate(() => {
      items.value = [];
    });

    // 3: 返出去的名称要与dom的ref相同, 这样就可以接收到dom的回调
    return {
      content,
      items
    };
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 4. 生命周期函数的使用

<template>
  <div>
    <button @click="add">点击增加, 触发updata</button>
    <p>{{obj.count}}</p>
  </div>
  <p>
    2.x与 3.0的对照
    beforeCreate -> 使用 setup()
    created -> 使用 setup()
    beforeMount -> onBeforeMount
    mounted -> onMounted
    beforeUpdate -> onBeforeUpdate
    updated -> onUpdated
    beforeDestroy -> onBeforeUnmount
    destroyed -> onUnmounted
    errorCaptured -> onErrorCaptured
  </p>
</template>

<script>

//这些生命周期注册方法只能用在 setup 钩子中
import { onMounted, onUpdated, onBeforeUnmount, reactive } from "vue";
export default {
  // 1: setup显得冗长, 可以自己动手做一些插件来优化
  // 2: 本身更加明确意图
  // 3: 需要树立工程师的正确代码意识
  // 4: 能力不足可能会写出更差的代码
  // 作者说: 提升上界的收益远远大于降低下界的损失。值得深思, 前端需要提高门槛
  // 5: 调用时机: 创建组件实例,然后初始化 props ,紧接着就调用setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用
  // 6: 这些生命周期钩子注册函数只能在 setup() 期间同步使用, 因为它们依赖于内部的全局状态来定位当前组件实例(正在调用 setup() 的组件实例), 不在当前组件下调用这些函数会抛出一个错误。
  // 7: 原则上生命周期里面不会放具体的逻辑,哪怕只有一句赋值一个三元都不可放, 这也正好符合当前的工程模式

  // 讨论: 有多少种方式, 可以判断出某个函数 当前处于哪个函数?
  //       比如有多层嵌套的组件是否有影响
  setup() {
    onMounted(() => {
      console.log("is mounted!");
    });
    onUpdated(() => {
      console.log("is onUpdated!");
    });
    onBeforeUnmount(() => {
      console.log("is onBeforeUnmount!");
    });
    const obj = reactive({
      count: 1
    });
    function add() {
      obj.count++;
    }
    return {
      obj,
      add
    };
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 5. 路由的使用方法

<template>
  <div>
    {{id}}
  </div>
</template>

<script>
import { getCurrentInstance, ref } from 'vue';
export default {
  setup(){
    const { ctx } = getCurrentInstance()
    // 1. 这样也是为了去掉this
    // 2. 方便类型推导
    console.log(ctx.$router); // push等方法
    console.log(ctx.$router.currentRoute.value); // 路由实例
    // 这个其实没有必要变成ref因为这个值没必要动态
    // 但是他太长了, 这个真的不能忍
    const id = ref(ctx.$router.currentRoute.value.query.id)

    // 4: 页面拦截器
    ctx.$router.beforeEach((to, from,next)=>{
      console.log('路由的生命周期')
      next()
    })
    return {
      id
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 6. vuex 的使用方法

import { createStore } from 'vuex'

// 难道前端趋势只有函数这一种吗
export default createStore({
  state: {
    name:'牛逼, 你拿到我了',
    age: 24,
    a:'白',
    b:'黑'
  },
  mutations: {
    updateName(state, n){
      state.name += n
    }
  },
  actions: {
    deferName(store) {
     setTimeout(()=>{
       // 必须只有commit可以修改值, 这个设定我比较反对, 可以讨论
       // vuex本身结构就很拖沓, 定义域使用个人都不喜欢
      store.state.name = '牛逼, 你改回来了'
     },1000)
    }
  },
  getters: {
    fullName(state){ return `${state.a} - + -${state.b}` }
  },
  modules: {
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
  <div>
    <p>{{name}}</p>
    <button @click="updateName('+')">点击改变名字</button>
    <br />
    <button @click="deferName('+')">改回来</button>

    <p>{{fullName}}</p>
  </div>
</template>

<script>
import { useStore } from "vuex";
import { computed } from "vue";
export default {
  setup() {
    const store = useStore();
    // 1: 单个引入
    const name = computed(() => store.state.name);
    // 2: 引入整个state
    const state = computed(() => store.state);
    console.log("vuex的实例", state.value); // 别忘了.value

    // 3: 方法其实就直接从本体上取下来了
    const updateName = newName => store.commit("updateName", newName);

    // 4: action一个意思
    const deferName = () => store.dispatch("deferName");

    // 5: getter 没变化
    const fullName = computed(() => store.getters.fullName);
    return {
      name,
      fullName,
      deferName,
      updateName,
    };
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 7. composition 使用方法

composition 使得前端工程师的编程规范,更接近于原生js。

另外,我们在开发工程而不是插件的话,还是不要使用mixin了,这东西无法追溯来源,搞得语义太差了,例如:

<template>
  <div>
    <button @click="addN1">上面的增加</button>---> {{n1}}
  </div>
   <div>
    <button @click="addN2">下面的增加</button>---> {{n2}}
    <button @click="addN210">每次n2+10</button>
  </div>
  <div>
    <p>组件里面也可以如此引用, 这就可以代替mixin一部分功能了</p>
    <button @click="addN3">n3的增加</button>---> {{n3.value}}
  </div>
  <div>
    <com></com>
  </div>
</template>

<script>
import { ref} from 'vue';
import n3Change from './mixin';
import com from '../components/composition.vue';

export default {
  components:{
    com
  },
  setup(){
     // 1: setup只是一个整合函数
     // 2: 甚至整个函数里面可能会没有具体的逻辑
     // 3: 以此推断, ref等方式定义的变量, 会自动识别在哪个setup内部, 从而达到逻辑的复用
     // 4: 由此方法可以很好的代替mixin了
     // 5: 当然, 这里也可以截获数据,来做一些事情
     const {n2, addN2} = n2Change();
     function addN210(){
       n2.value += 10
     }
     return {
       ...n1Change(),
       ...n3Change(),
       n2,
       addN2,
       addN210
     }
  }
}
// 甚至已经可以写在任何地方了, 响应式自由度大大提高
function n1Change(){
   const n1 = ref(1);
   let addN1 = ()=>{
     n1.value++
   }
   return {
     n1,
     addN1
   }
}

function n2Change(){
   const n2 = ref(1);
   let addN2 = ()=>{
     n2.value++
   }
   return {
     n2,
     addN2
   }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

写在任何地方, 然后导入就成了 mixin

import { reactive } from 'vue';

export default ()=> {
  const n3 = reactive({
    name: 'mixin',
    value: 1
  })
  const addN3=()=>{
    n3.value++
  }
  return {
    n3,
    addN3
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8. 关于插件的新思路

::: info 开发插件并不一定要挂载到vue的原型上 导致vue原型臃肿, 命名冲突等等(比如两个ui都叫 message) 原理就是 provide 和 inject, 依赖注入 :::

import {provide, inject} from 'vue';

// 这里使用symbol就不会造成变量名的冲突了, 这个命名权交给用户才是真正合理的架构设计
const StoreSymbol = Symbol()

export function provideString(store){
  provide(StoreSymbol, store)
}

export function useString() {

  const store = inject(StoreSymbol)

  return store
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

app.vue页面统一的初始化一下

export default {
  setup(){
    // 一些初始化'配置/操作'可以在这里进行
    // 需要放在对应的根节点, 因为依赖provide 和 inject
     provideString({
       a:'可能我是axios',
       b:'可能我是一个message弹框'
     })
  }
}
1
2
3
4
5
6
7
8
9
10

在需要使用的组件里面接收

<template>
  <div>
    插件的演示
  </div>
</template>

<script>
import { useString } from '../插件';

export default {
  setup(){
    const store = useString();
    // 不光是拿到值, 可以由app定义什么可以被拿到
    console.log('拿到值了',store)
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 9. 新观察者简单使用

<template>
  <div>
    <button @click="addn1">n1增加--{{n1}}</button>
    <button @click="addn2">n2增加--{{n2}}</button>
    <button @click="addn3">n3增加--{{n3}}</button>
  </div>
</template>

<script>
import { watch, ref } from "vue";
export default {
  setup() {
    const n1 = ref(1);
    const n2 = ref(1);
    const n3 = ref(1);
    // 1: 监听一个
    // 第一个参数是函数返回值, 当然也可以 直接写n1 
    // 如果监听的是一个对象里面的某个属性, 那就需要这种函数的写法了, 比2.x的字符串写法高明很多

    watch(
      () => n1.value,
      (val, oldVal) => {
        console.log("新值", val);
        console.log("老值", oldVal);
      }
    );
    // 2: 监听多个
    // 数组的形式定义多个, 这就出现问题了吧, 如果我观察的对象就是个数组, 并且每一项都是一个返回值的函数, 岂不是会被他误认为是多监控的结构, 苦恼
    watch(
      [() => n2.value, ()=>n3.value],
      ([val, val3],[val2, val4]) => {
        // val 是 n2的新值   val2是 n2的老值
        // val3 是 n3的新值  val4是 n3的老值
        console.log("新值 与 老值 是这种对应关系", val, val2);
        console.log("新值 与 老值 是这种对应关系", val3, val4);
      }
    );

    function addn1() {
      n1.value++;
    }
    function addn2() {
      n2.value++;
    }
     function addn3() {
      n3.value++;
    }
    return {
      addn1,
      addn2,
      addn3,
      n1,
      n2,
      n3
    };
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 10. 新的计算属性使用方法

别看 watchEffect 带个 watch ,但是他的功能可以归为计算属性里面

<template>
  <div>
    <button @click="addCount">点击计算</button>
    <button @click="setCount(1)">点击出发set</button>
    <p>count--{{count}}</p>
    <p>count2--{{count2}}</p>
    <p>count3--{{count3}}</p>
  </div>
</template>

<script>
// 弄得类似react了
import { computed, ref, watchEffect } from "vue";
export default {
  setup() {
    const count = ref(1);
    // 1. 默认的定义方式
    const count2 = computed(() => count.value * 2);
    console.log(count2.value); // 也要value因为可能是简单类型
    // 2. getter与setter当然可以定义
    const count3 = computed({
      get: () => count.value * 3,
      set: val => {
        // 这里重置了count
        count.value = val;
      }
    });
    // 3. watchEffect 更像是计算函数
    // 立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数
    // 侦听器会被链接到该组件的生命周期,并在组件卸载时自动停止。
    // Vue 的响应式系统会缓存副作用函数,并异步地刷新它, 比如同时改变了count与conut4此时watchEffect只是执行一次
    // 初始化运行是在组件 mounted 之前执行的。因此,如果你希望在编写副作用函数时访问 DOM(或模板 ref),请在 onMounted 钩子中进行
    // 并不是返回值, 而是监听里面所有的值, 任何有变化都会重新执行, 他应该可以玩出点东西。
    const count4 = ref(1);
    const stop = watchEffect(() => {
      if (count4.value) {
        console.log("作为判断条件也可以根据count4的变化而重新执行");
      }
      console.log(count.value);
    });
    setTimeout(() => {
      stop(); // 停止监听
    }, 10000);
    function addCount() {
      count.value++;
      setTimeout(() => {
        count4.value++;
      }, 1000);
    }
    // 触发setter
    function setCount() {
      count3.value = 2;
    }
    return {
      count,
      count2,
      addCount,
      count3,
      setCount
    };
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

# 11. customRef 简单使用(防抖)

当然这里说的防抖不是重点, 重点是这种代码的思维

<template>
  <div>
    <input type="text" v-model="text" />
  </div>
</template>

<script>
import { customRef, onUnmounted } from "vue";
export default {
  setup() {
    let timeout = null; // 并不需要响应式
    const text = useDebouncedRef("hello", (time) => {
      // 毕竟是延时的不用担心获取不到这个值
      console.log("延时执行回调", text.value);
      console.log('时间实例', time)
      timeout = time;
    });
    // 好习惯也是成为合格工程师的必要条件
    onUnmounted(()=>{
        clearTimeout(timeout);
    })
    return {
      text
    };
  }
};

// 并不用纯粹的js编写, 可以利用customRef来监控这个值的一举一动
// 写法一般, 但是思路又多了一条, 感谢
function useDebouncedRef(value, callback, delay = 200) {
  let timeout;
  // 两个参数分别是用于追踪的 track 与用于触发响应的 trigger
  // 这两个参数对 值的追踪 在当前并没有用,比如watchEffect的出发机制
  // 不调用这两个值没问题, 但是如果写成插件的话还是要调用的, 因为别人没准在追踪这个值,

  // 注意:  这个函数不可以有太大的delay, 如果超过500的话就需要考虑在组件销毁时候的清除定时器, 反而逻辑加深了, 此时我们可以每次把演示器的实例拿到
  return customRef((track,trigger) => {
    return {
      get() {
        track()
        return value;
      },
      set(newValue) {
        clearTimeout(timeout);
        // callback接受的太晚了, 可以在这里用另一个函数或对象接收
        timeout = setTimeout(() => {
          value = newValue;
          trigger()
          callback(timeout);
        }, delay);
      }
    };
  });
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 12. 组件与注入

父级组件

<template>
  <div>
    组件:
    <zj :type="type" @ok="wancheng"></zj>
  </div>
</template>

<script>
import zj from "../components/子组件.vue";
import { ref } from 'vue';
import { provide } from 'vue'

export default {
  components: { 
    zj
  },
  setup() {
    provide('name','向下传值'); // 基础值
    provide('name2', ref('向下传值')); // 监控值
    const type = ref('大多数');

    function wancheng(msg){
      console.log('子组件-->',msg)
      setTimeout(()=>{
        type.value = 'xxxxxxx'
      },2000)
    }
    return {
      type,
      wancheng
    }
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

子组件

<template>
  <div>props的属性不用setup去return --- {{type}}</div>
</template>

<script>
import { inject, ref } from 'vue'
// 为了让 TypeScript 正确的推导类型,我们必须使用 createComponent 来定义组件:
export default {
  props: {
    type: String
  },
  // 1: props也是不可以解构的, 会失去响应式
  // 2: context是上下文, 我们可以获取到slots emit 等方法
  // 3: props, context 分开也是为了ts更明确的类型推导
  // setup({type}){
  setup(props, context) {
    // 1: props
    console.log("props", props.type);
    console.log("上下文", context);
    context.emit('ok','传递完成')

    // 2: 注入
    console.log('inject',inject('name'));
    console.log('inject',inject('xxxx','我是默认值'))
    inject('name1', ref('默认值')) // 接收方也可以这样
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#Vue
上次更新: 2024/01/30, 00:35:17
vue3+vite:本地代理,配置proxy
Vue3.0 挂载方法,添加全局属性

← vue3+vite:本地代理,配置proxy Vue3.0 挂载方法,添加全局属性→

最近更新
01
Gitea数据备份与还原
03-10
02
Linux 中使用 rsync 同步文件目录教程
03-10
03
Linux 使用 rsync 互相传输同步文件的简单步骤
03-08
更多文章>
Theme by Vdoing | Copyright © 2019-2025 NoteZ,All rights reserved | 冀ICP备2021027292号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式