写作时间2020-12月份
脚手架安装
vue提供了脚手架可以直接生成开发环境,可以全局安装vue-cli脚手架,安装命令
npm install yarn -g
//这里建议用 yarn 安装,npm 安装没有外网会装不上
yarn global add @vue/cli
//此处安装新版本,且安装到全局
vue -V // 查看 vue/cli 版本 此处是 4.3.1 版本
创建新项目
vue create project-vue
此处有一个选择,第一个 defalut 是默认的不包含 ts 编译支持的,需要选择 Manually select features 即手动选择添加 ts 支持
添加需要其他一些功能支持,此处上下按钮切换到对应栏,按空格添加活删除所需功能,此处选择 ts vuex router css 功能,然后 enter 下一步
是否使用 class 风格装饰器,原本 vue2 创建 class 是 class Demo extends Vue{}, 到了 vue3 可以不用这中方法,使用 Dome = new Vue() 即可,所以这里可以不选
- Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX) 是否需要支持 jsx,这里不需要,
- Pick a linter / formatter config 选择Linter / Formatter 代码规范类型,选择 standard 规范即可 规范地址
- Pick additional lint features: 语法检查方式,这里选择保存就检查
- Where do you prefer placing config for Babel, ESLint, etc. babel,eslint文件放在那里,
- Save this as a preset for future projects 将此设置保存为以后的通用设置,设为 n
- Pick the package manager to use when installing dependencies 包管理器用啥安装,这里选择yarn,
也可以使用另外一种方式创建项目控制台输入 vue ui 可以打开本地 8000 端口 localhost:8000
可以按照上面配置创建项目
项目目录
生命周期对比
beforeCreate -> use seup() created -> use setup() beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestory -> onBeforeUnmount destoryed -> onUnmounted activated -> onActivated deactivated -> onDeactivated errorCaptured -> onErrorCaptured 新增 onRenderTracked onRenderTriggered // 数据变化渲染的时候监听
数据响应demo (包含ref,computed)
- setUp 钩子函数,在 beforeCreate 创建之前使用,返回的数据在模板中直接使用,其中没有 this 属性,
- ref 可以监听基本数据类型的变化然后触发模板重新渲染,其以 value 值来访问数据
<template>
<div>
<div>{{age}}</div>
<div>{{three}}</div>
<button @click="add">加+1</button>
</div>
</template>
<script lang="ts">
import { computed, ref } from 'vue'
export default {
name: 'App',
setup () {
const name = ref('xx')
const age = ref(0)
const add = () => {
age.value++
}
const three = computed(() => {
return age.value * 3
})
return {
name,
age,
add,
three
}
}
}
</script>
点击 加+1 之后 age 就会跟着 +1
为了让数据放在一起更好看,可以用 reactive 创建数据,他会把数据,和操作方法包裹起来,使其看起来更整体
<template>
<div>
<div>{{data.age}}</div>
<div>{{data.three}}</div>
<button @click="data.add">加+1</button>
</div>
</template>
<script lang="ts">
import { computed, ref, reactive } from 'vue'
interface DataType {
age: number;
add: () => void;
three: number;
}
export default {
name: 'App',
setup () {
// 代码更整洁了
const data: DataType = reactive({
age: 0,
add: () => { data.age++ },
three: computed(() => data.age * 3)
})
return {
data
}
}
}
</script>
如果想直接获取 age, add, three 不用 data.xx 访问的话可以用 toRefs toRefs 函数可以将 reactive 创建出来的响应式对象转换为普通对象,这个对象上的每个属性节点,都是 ref 类型的响应式数据
<template>
<div>
<div>{{age}}</div>
<div>{{three}}</div>
<button @click="add">加+1</button>
</div>
</template>
<script lang="ts">
import { computed, ref, reactive, toRefs } from 'vue'
interface DataType {
age: number;
add: () => void;
three: number;
}
export default {
name: 'App',
setup () {
const data: DataType = reactive({
age: 0,
add: () => { data.age++ },
three: computed(() => data.age * 3)
})
const refData = toRefs(data)
return {
...refData
}
}
}
</script>
watch 用法
<template>
<div>
<div>{{age}}</div>
<div>{{three}}</div>
<div>{{arr[0]}}</div>
<div>{{title}}</div>
<button @click="add">加+1</button>
<button @click="updateTitle">改变title</button>
</div>
</template>
<script lang="ts">
import { computed, ref, reactive, toRefs, watch } from 'vue'
interface DataType {
age: number;
add: () => void;
three: number;
arr: [number];
}
export default {
name: 'App',
setup () {
const data: DataType = reactive({
age: 0,
add: () => { data.age++ },
three: computed(() => data.age * 3),
arr: [0]
})
const title = ref('')
const updateTitle = () => {
title.value = 'xx'
}
watch(title, () => {
document.title = title.value
})
const refData = toRefs(data)
return {
...refData,
updateTitle,
title
}
}
}
</script>
watch 也可以监听多个数据
watch([title, data], () => {
console.log(data)
document.title = title.value + '' + data.age
})
// 也可以函数形式只监听 data.age
watch([title, () => data.age], (oldVal, newVal) => {
console.log(oldVal, newVal)
document.title = title.value + '' + data.age
})
watchEffect
watchEffect 返回一个函数,函数里面可以直接只监听用到的字段的变化,其他字段不会触发watch
export default defineComponent({
name: "App",
setup() {
const name = ref("name:");
const age = ref(123);
setInterval(() => {
name.value += "1";
}, 2000)
setInterval(() => {
age.value += 3
}, 5000)
watchEffect(() => {
console.log("只打印age",age.value);
})
return {
name,
age
}
},
});
/*
只打印age 123
只打印age 126
只打印age 129
只打印age 132
只打印age 135
*/
onMounted, onUnmounted
以绑定点击获取鼠标点击位置事件来展示 onMounted, onUnmounted 的使用
<script lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
export default {
name: 'App',
setup () {
const x = ref(0)
const y = ref(0)
const updateMouse = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('click', updateMouse)
})
return {
x, y
}
}
}
</script>
这里可以把 移动 获取事件提取出一个 hooks 函数
import { ref, onMounted, onUnmounted } from 'vue'
function mousePostion () {
const x = ref(0)
const y = ref(0)
const updateMouse = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('click', updateMouse)
})
// 组件返回坐标 x,y
return {
x, y
}
}
export default mousePostion
// 引用上面的函数 直接使用
import mousePostion from './commonHooks/mousePostion'
export default {
name: 'App',
setup () {
// 调用时可直接获取值
const { x, y } = mousePostion()
return {
x, y
}
}
}
</script>
h 函数
vue中h函数是创建一个虚拟节点,然后插入节点。
import { createApp, defineComponent, h,ref } from "vue";
import store from "./store";
const App = defineComponent({
setup() {
const data = ref(1)
setInterval(() => {
data.value += 2
}, 2000)
// const renderData = data.value // 这里是setup函数只会触发一次,setup函数里面 return 的数据变化后函数会被多次调用,重新渲染,
return () => {
const renderData = data.value // 如果想重新定义简写数据,只有在这里定义数据,dom才会触发渲染
return h("div", { id: "app" }, [
h("div", renderData)
])
}
}
})
createApp(App)
.use(store)
.mount("#app");
telport
有时候像 Modal 框,Message 消息栏,我们希望是放在全局,跟 app 同级的地方使用的,
modal 组件,
<template>
<div class="modal">
modal
</div>
</template>
<script>
export default {
}
</script>
<style>
.modal{
padding: 20px;
border: 1px solid #ccc;
}
</style>
一般调用方法调用
<template>
<div>
<div>根</div>
<modal />
</div>
</template>
<script lang="ts">
import modal from './components/modal.vue'
export default {
name: 'App',
components: {
modal
}
}
</script>
modal 组件是处在 app 目录下的
使用teleport方法,
首先在 public/index.html 下面在 app 同级 添加一个 modal div, teleport 将要放到的地方
在对 modal 组件进行修改
<template>
<teleport to="#modal"> // 指定组件放到 modal div 上
<div class="modal">
modal
</div>
</teleport>
</template>
结果
事件传递 emit
<template>
<teleport to="#modal">
<div v-show="isOpen">
<div class="modal" v-show="isOpen">modal</div>
<button @click="buttonClick">modal事件</button>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
isOpen: Boolean
},
emits: {
close: (load: any) => { // 父级绑定的事件 @close 用法
return load.type === 'hello' // 这里返回数据判断,是否符合需要的数据,如果错误了,控制台会报警告,
}
},
setup(props, context) {
const buttonClick = () => {
context.emit('close', { // 设定一个子组件绑定的事件,及其传递的数据,
type: 'hello'
})
}
return {
buttonClick
}
}
})
</script>
<template>
<div>
<div>根</div>
<modal :isOpen="modalIsOpen" @close="closeModal" />
<div @click="showModal">openModal</div>
</div>
</template>
<script lang="ts">
import { ref } from 'vue'
import modal from './components/modal.vue'
export default {
name: 'App',
components: {
modal
},
setup() {
const modalIsOpen = ref(false)
const showModal = () => {
modalIsOpen.value = true
}
const closeModal = (rs: any) => {
console.log(rs)
modalIsOpen.value = false
}
return {
modalIsOpen,
showModal,
closeModal
}
}
}
</script>
Suspense 异步组件
suspense 可以加载一组异步组件,用法
<template>
<h1>{{result}}</h1>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
// 返回一个 promise
return new Promise((resolve) => {
setTimeout(() => {
return resolve({ // 最后返回 result
result: '成功'
})
}, 3000) // 3s 后返回
})
}
})
</script>
<template>
<div>
<Suspense> // 使用 suspense 包裹起来
<template #default> // #default 是默认需要加载的异步组件
<async-tel></async-tel>
</template>
<template #fallback> // 当异步组件没有返回的时候,加载一个
loading
<div>加载中...</div>
</template>
</Suspense>
</div>
</template>
<script lang="ts">
import AsyncTel from './components/AsyncTel.vue' // 引起组件
export default {
name: 'App',
components: {
AsyncTel
}
}
</script>
在 vscode 中 设置 vetur 属性,会把 ts 类解析到 template 模板中, vetur.experimental.templateInterpolationService = true