# 快速掌握Vue3 (opens new window)
# setup 函数
setup() 函数是 vue3 中,专门为组件提供的新属性。它为我们使用 vue3 的 Composition API 新特性提供了统一的入口. 它取代了 2.x中的beforeCreate 和Created钩子。
setup函数会在以下方法前执行
- Components
 - Props
 - Data
 - Methods
 - Computed Properties
 - Lifecycle methods
 
setup接受两个参数,props和 context,需要返回数据才能在模板中使用
- props: 用来接收 props 数据
 - context 用来定义上下文
 - 返回值: return {}, 返回响应式数据, 模版中需要使用的函数
 
代码示例
<template>
  <h1>{{name}}</h1>
</template>
<script>
import { ref,  watch } from 'vue'
export default {
  setup(props, ctx) {
    const name = ref('hello')
    setTimeout(() => {
      name.value = 'world'
    }, 2000)
    watch(name,(nv) => {
      console.log(nv)
    })
    return {
      name
    }
  }
}
</script>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# reactive 函数
reactive() 函数接收一个普通对象,返回一个响应式的数据对象。在setup函数创立完之后,需要返回整个对象,不能解构。 在模板中使用的时候会自动解开。
代码示例
<template>
  <h1>{{state.text}}</h1>
  <h1>{{text}}</h1>
</template>
<script>
import { ref,  watch, reactive } from 'vue'
export default {
  setup(props, ctx) {
    const state = reactive({
      text: 'hello world'
    })
    setTimeout(() => {
      state.text = "It's responsive"
    }, 1000)
    return {
      state,
      ...state
    }
  }
}
</script>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ref() 函数
对数据进行包装,然后返回一个响应式对象。要在js内读取返回的值需要执行 xxx.value的方式,然而在模板中使用可以不用写value。
代码示例
<template>
  <h1>{{text}}</h1>
</template>
<script>
import { ref } from 'vue'
export default {
  setup(props, ctx) {
    const text = ref('hello world')
    setTimeout(() => {
      text.value = "It's responsive"
    }, 1000)
    return {
      text
    }
  }
}
</script>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# isRef() 函数
isRef() 用来判断某个值是否为 ref() 创建出来的对象
# toRefs() 函数
toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象. 在setup函数解构也不会丢失响应式。对比reactive
DETAILS
<template>
  <h1>{{text}}</h1>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
  setup(props, ctx) {
    const state = reactive({
      text: 'hello world'
    })
    const refState = toRefs(state)
    setTimeout(() => {
      refState.text.value = "It's responsive"
    }, 1000)
    return {
      ...refState
    }
  }
}
</script>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# computed()
该函数用来创造计算属性,和过去一样,它返回的值是一个ref对象。 里面可以传方法,或者一个对象,对象中包含set()、get()方法
DETAILS
<template>
  <h1>{{fullName}}</h1>
</template>
<script>
import { computed } from 'vue'
export default {
  setup(props, ctx) {
    const state = reactive({
      first: 'hello ',
      last: 'world'
    })
    const fullName = computed(() => {
      return  state.first + state.last
    })
    setTimeout(() => {
      state.first = "hello, ...."
    }, 1000)
    return {
      fullName,
    }
  }
}
</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
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
# watch() 函数
watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是懒执行的,侦听的源数据变更时才执行回调。
- reactive定义的数据,watch的时候需要写方法,并返回对应属性的值
 - ref定义的数据可以直接watch
 
代码片段
<template>
  <h1>{{state.first + state.last}}</h1>
  <h1>{{count}}</h1>
  <button @click="change">state.first change</button>
  <button @click="count++">count++</button>
</template>
<script>
import { watch,reactive,ref } from 'vue'
export default {
  setup(props, ctx) {
    const state = reactive({
      first: 'hello ',
      last: 'world'
    })
    function change() {
      state.first = Math.random()
    }
    // 不能!!不能!!不能!!
    watch(state.first, (nv) => {
      console.log('state.first 数据是', state.first)
    })
    // 必须!! 必须!!必须!!
    watch(() => state.first, (nv) => {
      console.log('state.first 数据是', state.first)
    })
    // 或者
    const count = ref(0)
    watch(count, (nv) => {
      console.log('count 数据是', count.value)
    })
    watch([() => state.first,count], ([nfirst,ncount],[ofirst, ocount]) => {
      console.log('集中观测===========')
      console.log('nfirst:>> ', nfirst);
      console.log('ocount :>> ', ocount);
       console.log('ofirst :>> ', ofirst);
      console.log('ncount :>> ', ncount);
    })
    return {
      state,
      count,
      change
    }
  }
}
</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
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
# watchEffect() 函数
# LifeCycle Hooks(新的生命后期)
新的生命周期钩子需要从vue中按需引入,这些钩子只能在setup函数中使用
| vue2 | vue3 | 
|---|---|
| beforeCreate和created | setup | 
| beforeMount | onBeforeMount | 
| mounted | onMounted | 
| beforeUpdate | onBeforeUpdate | 
| updated | onUpdated | 
| beforeDestroy | onBeforeUnmount | 
| destroyed | onUnmounted | 
| activated | onActivated | 
| deactivated | onDeactivated | 
| errorCaptured | onErrorCaptured | 
| - | onRenderTracked | 
| - | onRenderTriggred | 
# Template refs
可以在模板中设置ref属性的值获取真实的DOM,
DETAILS
<template>
  <h1 ref="h1RefDom">hello</h1>
</template>
<script>
import { watch,reactive,ref, onMounted } from 'vue'
export default {
  setup(props, ctx) {
    const h1RefDom = ref(null)
    console.log('hRefDom :>> ', h1RefDom.value);
    onMounted(() => {
      // 获取到真实DOM
      console.log('hRefDom :>> ', h1RefDom.value.innerHTML);
    })
    return {
      h1RefDom
    }
  }
}
</script>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# vue 的全局配置
vue2.x中通过 Vue.prototype.$xxx =xxx
vue3.x中通过 app.config.globalProperties.$xxx 来配置
- errorHandler,指定一个处理函数,来处理组件渲染方法执行期间以及侦听器抛出的未捕获错误。这个处理函数被调用时,可获取错误信息和应用实例。
 - warnHandler,为 Vue 的运行时警告指定一个自定义处理函数。注意这只会在开发环境下生效,在生产环境下它会被忽略。
 - globalProperties, 添加可以在应用程序内的任何组件实例中访问的全局 property。属性名冲突时,组件的 property 将具有优先权。
 - isCustomElement
 - optionMergeStrategies,为自定义选项定义合并策略。
 - performance:设置为 true 以在浏览器开发工具的 performance/timeline 面板中启用对组件初始化、编译、渲染和更新的性能追踪
 
# Sharing State - 共享状态
DETAILS
usePromise.js
import { ref } from "vue";
export default function usePromise(fn) {
  const results = ref(null);
  // is PENDING
  const loading = ref(false);
  const error = ref(null);
  const createPromise = async (...args) => {
    loading.value = true;
    error.value = null;
    results.value = null;
    try {
      results.value = await fn(...args);
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  };
  return { results, loading, error, createPromise };
}
App.vue
import { ref, watch } from "vue";
import usePromise from "./usePromise";
export default {
  setup() {
    const searchInput = ref("");
    function getEventCount() {
      return new Promise((resolve) => {
        setTimeout(() => resolve(3), 1000);
      });
    }
    const getEvents = usePromise((searchInput) => getEventCount());
    watch(searchInput, () => {
      if (searchInput.value !== "") {
        getEvents.createPromise(searchInput);
      } else {
        getEvents.results.value = null;
      }
    });
    return { searchInput, ...getEvents };
  },
};
 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
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
# Suspense 组件
DETAILS
HelloWorld.vue
<template>
  <h1>{{ msg }} {{count}}</h1>
</template>
<script>
import { ref } from 'vue'
async function getResult() {
  return new Promise((resolve => {
    setTimeout(() => {
      resolve(Math.random()) 
    }, 1000)
  }))
}
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  async setup(props) {
    const count = ref(0);
    count.value = await getResult()
    return {
      count
    }
  }
}
</script>
App.vue
<template>
  <div>
    <div v-if="error">Uh oh .. {{ error }}</div>
    <Suspense>
      <template #default>
        <div>
          <HelloWorld :msg='"dsfs"'/>
        </div>
      </template>
      <template #fallback> Loading.... </template>
    </Suspense>
  </div>
</template>
<script>
import { ref, onErrorCaptured, defineAsyncComponent } from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default {
  components: {
    HelloWorld,
  },
  setup() {
    const error = ref(null);
    onErrorCaptured((e) => {
      error.value = e;
      // 阻止错误继续冒泡
      return true;
    });
    return { error };
  },
};
</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
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
# Teleport
DETAILS
App.vue
<template>
 <div style="position: relative;">
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <modal-button></modal-button>
    </div>
  </div>
</template>
<script>
import ModalButton from './components/ModalButton'
export default {
  components :{
    ModalButton
  }
}
</script>
components/ModalButton.vue
<template>
<teleport to="body">
  <button @click="modalOpen = true">
      Open full screen modal!
  </button>
  <div v-if="modalOpen" class="modal">
    <div>
      I'm a modal! 
      <button @click="modalOpen = false">
        Close
      </button>
    </div>
  </div>
  </teleport>
</template>
<script>
import { ref } from 'vue';
export default {
  setup() {
    const modalOpen = ref(false)
    return {
      modalOpen
    }
  }
}
</script>
<style>
.modal{
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.2)
}
</style>
 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
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
# 案例
# 生态
| 生态 | 地址 | 
|---|---|
| 官网 | https://v3.cn.vuejs.org/ | 
| 源码 | https://github.com/vuejs/vue-next | 
| vite构建器 | https://github.com/vitejs/vite | 
| 脚手架 | https://cli.vuejs.org/ | 
| vue-router-next | https://github.com/vuejs/vue-router-next | 
| vuex4.0 | https://github.com/vuejs/vuex/tree/4.0 | 
| vant2.x | https://vant-contrib.gitee.io/vant/next/#/zh-CN/ | 
| Ant Design of Vue 2.x | https://2x.antdv.com/docs/vue/introduce-cn/ | 
| element-plus | https://element-plus.org/#/zh-CN | 
| 模板解析器 | https://vue-next-template-explorer.netlify.app/ | 
| awesome-vite 官方集合 | https://github.com/vitejs/awesome-vite |