安装了node.js之后在cmd窗口执行创建vue工程的代码(直接在当前位置创建工程):
npm create vue@latest
报错
需要在node.js位置(C:\Program Files\nodejs)里面设置两个文件夹的权限为全部允许:
之后就可以正常创建
打开工程后出现代码爆红:
新建一个终端输入:
npm i
引入所以依赖。
启动代码工程:
终端运行代码:
npm run dev
停止:按ctrl+c
Vue2基本结构
index.html的body中留基本
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
App.vue中3个结构
<!-- html -->
<template>
</template>
<!-- js ts -->
<script lang="ts">
export default {
name:'App'
}
</script>
<!-- css -->
<style scoped>
.app {
padding: 20px;
}
</style>
在components文件夹中扩展其他vue文件(页面)
如何引入其他的vue,在script标签中引用
<!-- js ts -->
<script lang="ts">
import otherfrom "./components/Other.vue";
export default {
name:'App',
components:{other}
}
</script>
给按钮添加方法
在标签内用@click来指明点击方法
<button @click="changeAge">change Age</button>
然后在script区域添加(这里是在一个叫做Person的vue文件中)
<script lang="ts">
export default{
name:'Person',
data(){
return{
name:'zhangsan',
age:19,
tel:'1212121'
}
},
changeAge(){
this.age++;
}
}
</script>
vue3:区别就是只用一个setup,并且要把数据和方法return出去
setup是生命周期里最早的,所以vue2的写法可以获取setup里面的数据,但是不能反过来
(两个版本的写法可以共存)
<script lang="ts">
export default{
name:'Person',
setup(){
//数据
//非响应式
let name = 'zhangsan'
let age = 9
let tel = '129837823'
// 方法
function changeName() {
name = 'wangwu';
}
function changeAge() {
age ++;
}
function showTel() {
alert(tel);
}
return {name,age,changeName,changeAge,showTel}
}
}
</script>
可以简写成单独的一个<script>标签(回自动return)
<script setup lang="ts">
let name = 'zhangsan'
let age = 9
let tel = '129837823'
// 方法
function changeName() {
name = 'wangwu';
}
function changeAge() {
age ++;
}
function showTel() {
alert(tel);
}
</script>
如果要合并为一个<script>标签(如果页面名称和文件名称始终保持一致就不用改直接只用上面的就行)
先要安装vite插件,终端输入
npm i vite-plugin-vue-setup-extend -D
然后在vite.config文件中引入
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
再在plugins里面使用
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VueSetupExtend()//这个
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
最后就可以这样合并了
<script setup lang="ts" name="Person">
let name = 'zhangsan'
// 方法
function changeName() {
name = 'wangwu';
}
</script>
展示数据
在要展示的地方使用两个大括号括起来数据变量
<h2>age: {{age}}</h2>
对象类型:(car对象的brand和price数据)
<h2>One {{car.brand}} car ,value {{car.price}} million$</h2>
列表(循环)根据key去取对应的值( :key="g.id"也可以不用)
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
基本类型响应式数据
1,引入ref
import {ref} from 'vue'
2,给数据包裹ref()
let age = ref(9)
3,改变时数据名.value
age.value ++;
总共看起来应该是这样
<script setup lang="ts" name="Person">
import {ref} from 'vue'
let name = ref('zhangsan')
let age = ref(9)
let tel = '129837823'
// 方法
function changeName() {
name.value = 'wangwu';
}
function changeAge() {
age.value ++;
}
function showTel() {
alert(tel);
}
</script>
可以在设置中配置自动添加value
对象类型响应式数据
也可以用ref定义,value要写在对象后面
<script lang="ts" setup>
import {ref,reactive} from 'vue'
let games = ref([
{id:'001', name:'WarThunder'},
{id:'002', name:'WOT'},
{id:'003', name:'WOWS'}
])
function changeFirstGame(){
games.value[0].name = "Genshin"
}
</script>
如果要修改整个对象 (car对象,有brand和price属性)
car.value = { brand: 'Bad', price: 1 }
用reactive
1,引入reactive
import {reactive} from 'vue'
2,包裹住数据
let car = reactive({brand:'good',price:100})
直接改
car.price += 200
总共看起来是:
<script lang="ts" setup>
import {reactive} from 'vue'
//数据
let car = reactive({brand:'good',price:100})
//方法
function changePrice(){
car.price += 200
}
</script>
如果要改整个对象只能使用assign,不能直接赋值
function changeCar() {
Object.assign(car, { brand: 'Bad', price: 1 })
}
双向绑定数据
使用v-model
(这样会将输入框的值对应到script里面定义的firstName变量,同时可以通过输入框修改script里的值)
<input type="text" v-model="firstName">
计算属性Commuted
只在计算的值发生变化时才重新计算,有缓存 (方法无缓存)
<template>
<div class="Name">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
姓名:<span>{{ fullName }}</span>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
let firstName = ref('张')
let lastName = ref('三')
let fullName = computed(() => {
return firstName.value.slice(0, 1).toUpperCase() + firstName.value.slice(1) + lastName.value
})
</script>
commuted变量是只读类型,如果要改只能添加get()和set(val)方法,计算时(正常用法)就会走get()
监视Watch
引入
import { watch } from 'vue'
在script中使用watch,两个参数,一个是监视的对象sum,后面是改变时执行的函数
基本类型数据:
对象是由ref包裹的变量,但是不需要使用.value
//监视
const stopWatch = watch(sum, (newValue, oldValue) => {
console.log("changed "+newValue+","+oldValue)
//解除监视
if (newValue >= 10) {
stopWatch()//调用watch的返回值就停止监视了
}
})
对象类型数据:
也可以直接将对象放进来,但是无法监视内部值改变
注意日志console.log输出写法不同,使用+号显示不出对象,使用,可以看见
//监视
watch(car, (newValue, oldValue) => {
console.log("car 变了",newValue,oldValue)
})
添加第三个参数{deep:true}可以开启深度监视,可以监视内部值变化
//监视
watch(car, (newValue, oldValue) => {
console.log("car 变了",newValue,oldValue)
}, {deep:true})
</script>
添加immediate:true可以让页面打开时就监视一次
watch(car, (newValue, oldValue) => {
console.log("car 变了",newValue,oldValue)
}, {deep:true,immediate:true})
监听对象内的数据
首先必须是reactive包裹的
其次要写成方法返回值样式
基本类型和对象类型都这么写
// 监听单个值
watch(() => games[0].name, (newValue, oldValue) => {
console.log("games[1]name变了", newValue, oldValue);
})
对象类型还需要添加额外的{ deep: true}
监听多个数据watchEffect(自动)
无需写清楚监听什么变量,回调函数里使用了什么数据,那什么数据改变时就会监听,开始时自动监听一次
//自动监听
watchEffect(() => {
car.value.brand;
})
引入接口
在创建对象时如果需要接口,则需要通过import导入(在script标签内)
前面必须加type,@符号表示src目录
import { type inter } from '@/types';
接口需要添加export
export interface inter{
name: string;
age: number;
}
引入外部样式文件
直接在script标签内这样写,我这里放在src/css文件夹下
import '@/css/index.css'
接受其他地方传来的参数
直接传递defineProps
需要是直接写<Count :num>
import { defineProps } from 'vue';
//接受从其他地方传来的num
defineProps(['num']);
设定传递类型:
defineProps<{num:number}>();
父组件向子组件传递参数
<child />是这里定义的一个child.vue作为父组件的子组件展示在html部分的
props传递
父组件给子组件添加
<child :obj="obj"/>
子组件script部分声明并接收
defineProps(['obj'])
子组件向父组件传递参数
<child />是这里定义的一个child.vue作为父组件的子组件展示在html部分的
props传递
父组件先添加一个方法,通过方法的参数来获取子组件传递过来的参数
function getValue(value:string){}
同时要在组件中向子组件传递这个方法
<child :obj="obj" :giveValue="getValue"/>
子组件script部分声明并接收
defineProps(['obj', 'giveValue'])
giveValue('my value');
自定义事件
父组件给子组件绑定自定义事件
<child @fun1="fun"/>
<script setup lang='ts'>
import child from './child.vue'
function fun(value:number){
}
子组件声明事件
const emit = defineEmits(['fun1'])
调用
<button @click="emit('fun1',001)">Emit </button>
插槽(html占位)
默认插槽
父组件在创建子组件的时候写完整标签,可以在中间插入其他元素
注意样式要写在父组件的位置才能生效
<child>
<h1>Title</h1>
</child>
子组件要添加slot标签来占位,才能在子组件中展示插入的元素
<template>
<slot></slot>
</template>
具名插槽(添加名字选定插槽)
父标签需要额外添加一个template标签,使用v-slot:指定名称
<child>
<template v-slot:s1>
<h1>Title</h1>
</template>
</child>
可以简写成#插槽名
<child>
<template #s1>
<h1>Title</h1>
</template>
</child>
子组件要给插槽添加名字
<slot name="s1"></slot>
作用域插槽(父获取子数据)
子组件定位时添加数据
<slot :name="nameList"></slot>
let nameList = ([])
父组件添加slot参数
<child>
<template v-slot="params">
<h1>{{params.name}}</h1>
</template>
</child>
简写,取值时解构
<child>
<template v-slot="{name}">
<h1>{{name}}</h1>
</template>
</child>
常用指令(v-)
v-for(循环)
哪个元素要重复展示,v-for就写在那个元素上
v-for = “(下面要用到的单个数据,索引(可以省略)) in myList”
<div>
<tr v-for="(title,index) in myList">
<td>{{ title }}</td>
</tr>
</div>
v-bind(标签属性双向绑定)
v-bind : 属性名=“属性值”或者简写 :属性名=“属性值”
这个url需要在script中定义
<a v-bind:href="myUrl">
v-model(数据双向绑定)
v-model="数据"
<input type="text" v-model="age"/>
v-if和v-show(控制元素显示和隐藏)
v-if=“表达式”(true就展示,false元素不存在)有if else-if else
<div v-if="age>18">大于18岁</div>
<div v-else-if="age<8">小于8岁</div>
<div v-else>8岁到18岁</div>
v-show=“表达式”(true展示,false用display隐藏显示)
<div v-show="age<8">小于8岁</div>
v-on或@事件(绑定函数事件)
v-on:事件=“函数”,@事件=“函数”
<button v-on:click="fun1"></button>
<button @click="fun1"></button>
钩子函数(生命周期)
创建前:beforeCreate
创建后:created
载入前:beforeMount
挂载完成:mounted(常用,相当于onEnable)
onMounted(() => {
//代码
})
数据更新前:beforeUpdate
数据更新后:updated
组件销毁前:beforeUnmount
组件销毁后:unmounted