创建 vue3 项目,基于 vite
npm init @vitejs/app appname
npm install vue-router@4
vue3 基于 webpack 改 vite
1、复制 scr 目录
2、复制 package.json 中的 dependencies
3、npm i 安装依赖,并 npm run dev 修改 bug
vue2 基于 webpack 改 vite
1、复制 scr 目录
2、复制 package.json 中的 dependencies
3、npm i 安装依赖,
4、安装报错的 npm install @vue/compiler-sfc vue-template-compiler -S 和 npm install vite-plugin-vue2 -D
5、vite.config.js 修改
import { defineConfig } from 'vite'
import {createVuePlugin} from 'vite-plugin-vue2'
export default {
plugins: {
createVuePlugin()
}
}
5、npm run dev 修改路径、router 等 bug
vue2 和 vue3 区别
vue2 采用 Object.defineProperty(),1、不能监听数组的变化,2、必须遍历对象每一个属性
vue3 采用 proxy, 不需要遍历对象每一个属性。
vue3
ref() 基本类型
reactive() 对象
setup 语法糖插件:unplugin-auto-import 解决场景:在组件开发中无需每次都手动引入
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), AutoImport({ imports: ["vue", "vue-router"] })], // 自动导入vue和vue-router相关函数
});
toRefs 用于 解构对象、数组时 保持响应状态。
obj=Reactive{
name:'san',
sex:1
}
return {
...toRefs(obj)
}
computed,可以用get()\set()
let msg = ref("sdfsfsere fs");
let msgchange = computed(() => {
return msg.value.slice(1, 3);
});
return {
msg,
msgchange,
};
watch
// vue2
<template>
<div><input type="text" name="" v-model="msg">{{msg}}</div>
</template>
<script>
export default {
data() {
return {
msg:'hello',
obj: {
a:1
}
}
},
watch: {
msg(newVal,oldVal) {
console.log(newVal,oldVal)
},
obj: {
handler(newVal,oldVal) {
console.log(newVal,oldVal)
},
immediate: true, // 获取初始化的值
deep:true // 深度获取
}
}
}
</script>
// vue3
<template>
<div><input type="text" name="" v-model="msg">{{msg}}</div>
<div><input type="text" name="" v-model="str">{{str}}</div>
</template>
<script setup>
export default {
setup() {
let msg = ref("hello");
let str = ref("oo")
let obj= reactive({
a:2,
arr:['a','b','c']
})
// 方式一,单独监听
watch(msg,(newVal,oldVal) {
console.log(newVal,oldVal)
},{immediate:true}) // hello,undefined
// 方式二,监听多个值,一起监听
watch([msg,str],(newVal,oldVal) {
console.log(newVal,oldVal)
},{immediate:true})
// 监听对象的 某个属性
watch(()=>obj.arr,(newVal,oldVal) {
console.log(newVal,oldVal)
},{immediate:true})
return {
msg
}
}
}
</script>
组合监听
const nums = ref(9)
const demo = reactive({
name: '前端小玖',
nickName: '小玖',
soulmate: {
name: '',
nickName: ''
}
})
什么是组合监听呢?举个例子,比如我想同时监听 demo 对象的 name 属性,和基础类型 nums,只要他们其中任何一个发生变更,那么就触发 watch 方法。
watch([() => demo.name, nums], ([newName, newNums], [oldName, oldNums]) => {
console.log('watch 已触发: name', newName)
console.log('watch 已触发: nums', newNums)
})
注意,此时的第一个参数是一个数组,且第二参数箭头函数的参数也是数组的形式。
路由
useRoute => this.route
useRouter => this.router
import { useRouter } from 'vue-router';
let router = useRouter()
let go =()=> {
router.push('/about')
}
// 导航守卫
router.beforeEach((to, from, next) => {
if (to.name !== "Login" && !isAuthenticated) next({ name: "Login" });
else next();
});
组件传值 父传子
vue2、vue3通用方式
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son :for-child-msg="msg"></Son>
</div>
</template>
<script>
import Son from '../components/Son.vue'
export default {
components: {
Son
},
data() {
return {
msg:'这是父传给子的数据'
}
}
}
</script>
// Son
<template>
<div>
这是son组件
{{msg}}
</div>
</template>
<script>
export default {
props:{'forChildMsg':String}
data() {
return {
ownChildMsg:this.forChildMsg
}
},
watch: {
forChildMsg() {
this.ownChildMsg = this.forChildMsg
}
}
}
</script>
修改 props 数据
1.定义一个局部变量,并用 prop 的值初始化它,只有默认值传递给了 ownChildMsg,父组件改变只会变化到 forChildMsg,不会修改 ownChildMsg。
props: {
"for-child-msg": String
},
data() {
return { ownChildMsg: this.forChildMsg };
}
```
2. 定义一个计算属性,处理 prop 的值并返回
```js
props: {
"for-child-msg": String
},
computed: {
ownChildMsg() {
return this.forChildMsg + "---ownChildMsg";
}
}
```
3. 最推荐的方式是使用变量存储 prop 的初始值,并用 watch 来观察 prop 值得变化。发生变化时,更新变量的值。
```js
props: {
"for-child-msg": String
},
data() {
return {
ownChildMsg: this.forChildMsg
};
},
watch: {
forChildMsg() {
this.ownChildMsg = this.forChildMsg;
}
}
```
#### vue3 方式一 setup语法糖方式
```js
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son :for-child-msg="msg"></Son>
</div>
</template>
<script setup>
import Son from '../components/Son.vue'
let msg = ref('这是父传给子的数据')
</script></code></pre>
<pre><code class="language-js">// Son
<template>
<div>
这是son组件
{{msg}}
</div>
</template>
<script setup>
import {defineProps} from 'vue'
const props = defineProps({
'forChildMsg':{type:String,default:"111"}
})
const {forChildMsg:msg} = toRefs(props) // 重命名解构
}
</script>
</code></pre>
<h4>vue3 方式二 setup props接受</h4>
<pre><code class="language-js"><script lang="ts">
import { toRefs } from 'vue'
interface Data {
[key:string]:unknown
}
export default {
props:{
text:{
type:String,
default:""
},
message:Number
},
setup(props:Data){
const {text} = toRefs(props)
const formatText = <code>Hi,${text.value}</code>
return {
formatText
}
}
}
</script></code></pre>
<h3>组件 子传父</h3>
<h4>vue2子传父</h4>
<pre><code class="language-js">// Son
<template>
<div>
这是son组件
{{ownChildMsg}}
<button @click="toFatherMsg">自定义子传父</button>
</div>
</template>
<script>
export default {
data() {
return {
ownChildMsg:1111
}
},
methods: {
toFatherMsg() {
this.$emit('fn',this.forChildMsg)
}
}
}</code></pre>
<p>```js
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son :for-child-msg="msg" @fn="changeMsg"></Son><br />
</div>
</template>
<script>
import Son from '../components/Son.vue'
export default {
components: {
Son
},
data() {
return {
msg:'这是子传给父的数据'
}
},
methods: {
changeMsg(value) {
console.log(value) // 子组件传过的的值“1111”
this.msg = value
}
}
}</p>
<pre><code>#### vue3子传父 方式一 setup api
```js
// Son
<template>
<div>
这是son组件
{{ownChildMsg}}
</div>
<button @click="toFatherMsg">自定义子传父</button>
</template>
<script>
export default {
data() {
return {
ownChildMsg:1111
}
},
setup(props,{emit}) {
let ownChildMsg = ref(100);
const toFatherMsg = () => {
emit('fn',toFatherMsg)
}
}
}
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son :for-child-msg="msg" @fn="changeMsg"></Son>
</div>
</template>
<script>
import Son from '../components/Son.vue'
export default {
components: {
Son
},
setup () {
let msg =ref(200)
let changeMsg(value) = (value)=>{
console.log(value) // 子组件传过的的值“1111”
msg.value = value.value
}
return {
changeMsg,
msg
}
}
}
vue3子传父 方式二 setup 语法糖
// Son
<template>
<div>
这是son组件
{{toFatherMsg}}
<button @click="toFatherMsg">自定义子传父</button>
</div>
</template>
<script setup lang='ts'>
let toFatherMsg = ref("111")
// const emit = defineEmits<{(e:'fn',id:number):void}>() // ts方式
const emit = defineEmits(['fn']) // setup方式
const toFatherMsg = () => {
emit('fn',toFatherMsg)
}
}
}
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son :for-child-msg="msg" @fn="changeMsg"></Son>
</div>
</template>
<script setup>
import Son from '../components/Son.vue'
export default {
components: {
Son
},
data() {
return {
msg:'这是子传给父的数据'
}
},
methods: {
changeMsg(value) {
console.log(value) // 子组件传过的的值“1111”
this.msg = value
}
}
}
组件 v-model传值,即实现父子组件双向绑定修改
// father
<template>
<div>
<div>
<span>父组件数据</span>
<input v-model="msg"/>
</div>
这是父组件,htmlz中需要用kebab-case命名,字符串模板没有这一限制
<Son v-model:for-child-msg="msg" @fn="changeMsg"></Son>
</div>
</template>
<script setup>
import Son from '../components/Son.vue'
export default {
components: {
Son
},
data() {
return {
msg:'这是子传给父的数据'
}
},
methods: {
changeMsg(value) {
console.log(value) // 子组件传过的的值“1111”
this.msg = value
}
}
}
// Son
<template>
<div>
这是son组件
{{toFatherMsg}}
<button @click="toFatherMsg">双向绑定的子传父</button>
这是父传子的数据:{{for-child-msg}}
</div>
</template>
<script setup >
const props = defineProps({
'forChildMsg':{
type:Number,
default:20
}
})
let toFatherMsg = ref("111")
// const emit = defineEmits<{(e:'fn',id:number):void}>() // ts方式
const emit = defineEmits(['update:forChildMsg']) // setup方式
const toFatherMsg = () => {
emit('update:forChildMsg',toFatherMsg)
}
}
}