可以做行程的网站,网站详情怎么做的,推广网站怎么做模版,客户管理系统免费一、基础准备工作
#xff08;一#xff09;过程
环境要求#xff1a;有node.js环境、npm。执行命令#xff1a; npm create vuelatest 而后选择#xff1a; ✔ 请输入项目名称#xff1a; … me_vue3
✔ 是否使用 TypeScript 语法#xff1f; … 否 / 是
✔ 是否启用…一、基础准备工作
一过程
环境要求有node.js环境、npm。执行命令 npm create vuelatest 而后选择 ✔ 请输入项目名称 … me_vue3
✔ 是否使用 TypeScript 语法 … 否 / 是
✔ 是否启用 JSX 支持 … 否 / 是
✔ 是否引入 Vue Router 进行单页面应用开发 … 否 / 是
✔ 是否引入 Pinia 用于状态管理 … 否 / 是
✔ 是否引入 Vitest 用于单元测试 … 否 / 是
✔ 是否要引入一款端到端End to End测试工具 › 不需要
✔ 是否引入 ESLint 用于代码质量检测 … 否 / 是只有TS选择是即可。 最后项目创建成功进入后根据提示安装两个插件并执行命令 npm install
二文件结构
.vscode文件中extensions.json是官方给vscode做的插件信息Vue.volar, Vue.vscode-typescript-vue-plugin进入项目后会自动提示进行安装。node_modules中都是项目依赖的包。public中是公共资源favicon.ico是网页的页签图标。src是项目的核心assests是放静态资源的文件夹里面是一些css样式等静态资源components中是很多组件App.vue是根组件每个组件都挂载载App组件上main.js中主要将根组件挂载。.gitgnore是git中一些忽略文件里面出现的声明在推拉过程中会被忽略。env.d.ts中指定了很多文件类型如jpg等如果没有此文件则ts不会认识jpg等格式的文件。index.html 程序的入口页面里面有Id号为App的Div。package-lock.json package.json 一个关于webpack的配置信息。README.md是一些关于该项目的说明文本文件。tsconfig.app.json ts tsconfig.json tsconfig.json tsconfig.node.json的配置文件。vite.config.tsvite的配置文件。 这里介绍下vitevite是Vue3新引入的项目构建工具构建速度要比Vue2更快同时实现了按需加载当我们需要哪些时哪些部分才会被加载。 三重要文件的简单认识
index.html
!DOCTYPE html
html langenheadmeta charsetUTF-8!--规定字符编码方式--link relicon href/favicon.ico!--引入页签图标--meta nameviewport contentwidthdevice-width, initial-scale1.0!--移动端适配--titleVite App/title/headbodydiv idapp/div!--命名为app是App组件加载的地方--script typemodule src/src/main.ts/script!--引入main.ts,由其负责将App组件加入到该位置挂载--/body
/htmlmain.ts
import ./assets/main.cssimport { createApp } from vue//从vue中引入createApp负责创建组件并挂载到#app元素。
import App from ./App.vue //引入App组件createApp(App).mount(#app); //创建App组件根组件并挂载到#app元素。四重写src文件
重写APP组件(Vue2写法
main.ts无变化
App.vue:
template
!--vue3不需要最外层的根元素--div ididContain破天荒Person/Person/div
/templatescript langts
import Person from ./components/Person.vue;
export default {name: App,components:{Person,}
}
/scriptstyle#idContain{border-radius:5px;border: gray solid 2px;background-color: burlywood;box-shadow: 3px 4px black;}
/style
Person.vue:
templatediv idpersonContainh2{{ name }}/h2h2{{ sex }}/h2button clickgetTel点我获取联系方式/buttonbutton clickchangeName点我改变姓名/buttonbutton clickchangeSex点我改变性别/button/div
/templatescript langts
export default {name:Person,data(){return{name:小明,sex: 男,tel: 19999999999}},methods:{changeName(){console.log(one);if(this.name 小李){this.name 小飞;}else{this.name 小胡;}},changeSex(){this.sex女?男:女;},getTel(){alert(this.tel);},}
}
/scriptstyle#personContain{border: 2px solid black;background-color: yellowgreen;border-radius: 2px;}
/style
注意Vue3中可以使用Vue2语法但是现在我们这种写法下的数据不是响应式的虽然函数会执行data中的数据发生了改变但是并未被渲染到页面中
选项式API和组合式API
Vue2是选项式写法Vue3是组合式写法
Vue2选项式的缺点每当有某个业务需要改变时关涉到数据信息业务逻辑等信息要在data、method等等选项中寻找相关内容增加维护成本。
Vue3组合式写法的优点所有关于一个业务的数据方法等等都写在一块儿这样就方便业务维护。
再重写组件内容Vue3写法
export default {name:Person,setup(){let name 小明;//因为数据和逻辑在一块所以this的作用被弱化let sex女; //注意这里声明的数据需要返回才能被模版捕获let tel 1999999999;//注意数据仍然不是响应式的function getTel(){alert(tel);}function changeName(){name 小李;}function changeSex(){sex女?男:女;}//返回return {name,sex,tel,changeName,changeSex,getTel}}
}
//未出现部分不变
/script通过测试得知setup函数的执行时机要在beforeCreate之前这进一步可以看出是弱化了this的作用。
data、method、setup同用
setup是否能够得到data中的数据那反过来data是否能够得到setup中的数据
因为setup要在beforeCreate声明周期之前所以setup中不能获取data或者method的数据或方法同样因为data和method是在beforeCreate方法之后声明的所以它们可以得到setup中的数据。
data中使用setup中的数据
data(){return{name:this.name,}},
setup返回类型
返回对象类型中间属性是要被渲染的属性。返回方法该方法是渲染函数返回值会覆盖整个模版。
setup语法糖
考虑到大量业务书写时极易忘记将属性和方法返回所以可以用如下方式代替setup函数
script setup
let name 小明;//因为数据和逻辑在一块所以this的作用被弱化let sex女; //注意这里声明的数据需要返回才能被模版捕获let tel 1999999999;//注意数据仍然不是响应式的function getTel(){alert(tel);}function changeName(){name 小李;}function changeSex(){sex女?男:女;}
/script
其中内容和setup内容一致同时不需要我们进行返回处理自动返回变量和函数这样我们项目中一个vue文件就两个script标签了
缩写script
sudo npm i vite-plugin-vue-setup-extend
在vite.config.ts中引入并使用
import { fileURLToPath, URL } from node:urlimport { defineConfig } from vite
import vue from vitejs/plugin-vue
import VueViteExtend from vite-plugin-vue-setup-extend //引入// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),VueViteExtend(),//使用],resolve: {alias: {: fileURLToPath(new URL(./src, import.meta.url))}}
})
二、ref、reactive与响应式
一ref使用基本类型响应式、对象类型亦可
import {ref} from vue;
把要变为响应式的数据用ref函数包裹即可让数据成为响应式数据。
let name ref(小明); 结构 通过变量的value属性更改引起模版自动变化。
function changeName(){
name.value 小李;}
ref中也是调用了reactive的方法
一a 利用ref防止命名冲突
场景模拟App组件和Person组件中都有id为divOne的元素要输出利用getElementById获取元素输出会产生冲突
App组件 div ididContain破天荒 Person/Persondiv iddivOne我是app组件中的元素/div button clickoutElement输出元素/button/divfunction outElement(){let elementOne document.getElementById(divOne);if(elementOne ! null){console.log(elementOne.innerHTML);}}
Person组件
div idpersonContaindiv iddivOne refdivRefOne我想要更好的生活/divbutton clickoutElementOne输出元素/button/divfunction outElementOne(){let elementOne document.getElementById(divOne);if(elementOne ! null){console.log(elementOne.innerHTML);}}
输出结果 解决方法使用ref标记修改如下(以Person为例二者一致
//1
div refdivOne我是app组件中的元素/div
//2
let divOne ref();
function outElement(){ console.log(divOne.value)}一b当ref标记的是子组件时需要子组件暴露后才能输出具体内容
//appPerson refdivOne/Personbutton clickoutElement输出元素/button
//app scriptlet divOne ref();
function outElement(){ console.log(divOne.value)}子组件不暴露输出结果 子组件暴露 let one 我是即将要暴露的数据;let two 我是也是即将要暴露的数据;defineExpose({one,two});
结果 二reactive使用对象类型响应式
import {reactive} from vue;
对象深度响应无论多深都能实时响应到模版
对象
模版
divh2我的家人有{{ family.one.name}}和{{ family.two.name }}/h2button clickchangeFamilyName改变家人姓名/button/divscript//验证对象响应式let family reactive({one:{name:张金平,age:74},two:{name:陈玉丽,age:45}});function changeFamilyName(){family.one.name 张金平和陈志俭;family.one.age 53;}
数组亦然
模版
h2
我喜欢的动漫角色有{{ cotton[0].name }}、{{ cotton[1].name }}、{{ cotton[2].name }}
/h2
button clickchangeCottonName改变漫角姓名/button
script:
let cotton reactive([{name:美杜莎女王,age:23},{name:山内樱良,age:18},{name:02,age:22}])function changeCottonName(){cotton[0].name 阳菜;}
三两个方法的区别
a、对象整体替换 ref可以直接替换仍然响应式 let cotton
ref([{name:美杜莎女王,age:23},{name:山内樱良,age:18},{name:02,age:22}])function changeCottonName(){cotton.value [{name:清漪,age:24},{name:小鸟游六花,age:18},{name:daring,age:24}];//响应式} reative不可以直接替换要使用Object.assign方法 let cotton reactive([{name:美杜莎女王,age:23},{name:山内樱良,age:18},{name:02,age:22}])function changeCottonName(){// cotton [{name:清漪,age:24},{name:小鸟游六花,age:18},{name:daring,age:24}];//非响应式Object.assign(cotton,[{name:清漪,age:24},{name:小鸟游六花,age:18},{name:daring,age:24}]);//响应式} b、对象属性的传递响应 深拷贝
//一般深拷贝地址值let arrOne cotton[0];function changArrOne(){arrOne.name彩鳞;//改掉后cotton也会受影响。}
浅拷贝用到toRefs方法,地址附着但不会实时响应 //一般深拷贝地址值let cotton {name:美杜莎,age:33}; let {name,age} toRefs(cotton);// let name toRef(cotton,name);function changArrOne(){name.value 彩鳞;//改掉后cotton也会受影响。console.log(name.value);}
三、computed函数、watch函数
一computed函数 let firstName chen;let endName pei;let allNamecomputed((){return firstName endName});
computed整体被修改可以触发setter获取出发getter
let firstName ref(chen);let endName ref(pei);const allNamecomputed({get(){return firstName.value endName.value;},set(value){firstName.valuevalue.split(,)[0];endName.valuevalue.split(,)[1];}});function changAllName(){allName.value陈,佩;}
二watch函数、watchEffect函数
能够监视的四种类型ref定义的数据、reactive定义的数据、函数返回一个值getter函数、一个包含上述内容的数组监视普通变量 let firstName ref(chen);let endName ref(pei);function changFirstName(){firstName.value 张;}watch(firstName,(newValue,oldValue){console.log(姓发生了变化);})
监视对象ref let allName ref({firstName:陈,endName:佩})function changFirstName(){allName.value.firstName 张;}//第三个参数中使用deep配置项开启深度监视watch(allName,(newValue,oldValue){console.log(姓发生了变化);},{deep: true})//默认没有深度监视只会监视整个对象全部的变化。
注意监视对象整体改变后newValue和oldValue分别是之前对象和新对象如果对象某个属性发生改变新旧值相同。
监视对象reactive let allName reactive({firstName:陈,endName:佩,lover:{name:傻妞,birth: 2008}})function changeFirstName(){allName.firstName 张;}function changeLoverName(){allName.lover.name 陆小千;}watch(allName,(newValue,oldValue){console.log(姓或者lover名字发生了变化);})//默认深度监视无法手动取消深度监视
仅监视对象中某个属性
//只需把要监视的属性用函数返回即可完成监视
watch(() allName.lover.name,(newValue,oldValue){console.log(lover名字发生了变化);})
监视多个可监视类型组成的集合
let allName reactive({firstName:陈,endName:佩,lover:{name:傻妞,birth: 2008}})let outB ref({number:2,age: 23});function changeLoverName(){allName.lover.name 陆小千;}function addNumberOne(){outB.value.age 1;}watch([() allName.lover.name,outB,()outB.value.number],(newValue,oldValue){console.log(lover名字,姓名或者outB发生了变化);},{deep: true})//这里有ref数据所以要开启深度监视
watch解除监视 //返回一个函数类型用于解除监视let closeWatch watch(outB,(newValue,oldValue){console.log(lover名字,姓名或者outB发生了变化);if(newValue.age 24){closeWatch();//关闭监视}},{deep: true})
watchEffect自动监视
//会自动判断出现在条件中需要监视的数据并进行监视watchEffect((){if(outB.value.age 28){alert(年龄有点大了可以考虑结婚了朋友);}else if(allName.firstName 张){alert(大哥姓也要改呀);}})
四、数据暴露与接收
一父组件向子组件传递数据
传递 Person :testOnetestOne :testTwotestTwo/Person
//子组件
接收
// 接收父组件传来的数据testOnetestTwodefineProps([testOne,testTwo]);
注define开头函数为宏函数不需要import即可直接使用
二子组件向父组件传递数据
暴露子组件
//测试子组件暴露数据let testSonOne i am super man!;let testSonTwo i am your lover!;//暴露属性defineExpose({testSonOne,testSonTwo});
使用父组件 Person refsonComponent/Person
!--父组件中子组件形式--//获取子组件根据子组件标签中ref标识;let sonComponent ref();//获取子组件暴露属性function showData(){console.log(sonComponent.value.testSonOne);}
注意模版加载顺序为子组件-》父组件
四、生命周期
一Vue2和Vue3对比
beforeCreat 创建前setupcreated 创建后beforeMount 挂载前onBeforeMountmounted 挂载后onMountedbeforeUpdate 更新前onBeforeUpdateupdated 更新后onUpdatedbeforeDestroy 销毁前onBeforeUnmount 卸载前destroyed 销毁后onUnmounted 卸载后 五、hooks与组合式API
一两个功能实现原方式
div idpersonContaindiv idnumDiv!-- 功能一部分 --h3现在的数字是{{ numNow }}/h3button clicknumAddOne数字加一/button/divdiv idmottoDiv!-- 功能二部分 --li v-for(motto,index) in mottoList :keyindex{{ motto }}/libutton clickmottoAddOne增加格言/button/div/div
//结构部分
//数据let numNow ref(0);let mottoList ref([早起的鸟儿有虫吃]);//方法function mottoAddOne(){//从网站获取格言axios.get(https://v1.hitokoto.cn/?cfencodetext).then((data){//将数据插入数组mottoList.value.push(data.data);},(error){alert(出错了好小子 error)});}function numAddOne(){numNow.value 1;}
数据和方法在一块维护有困难
二使用hook方式
创建文件夹并创建两个功能相关ts注意文件命名使用驼峰式非大驼峰
将两个功能相关的数据放入到文件中
mottoAdd:
import {ref,onMounted} from vue;
import axios from axios;
export default function(){
//数据
let mottoList ref([早起的鸟儿有虫吃]);
//方法
function mottoAddOne(){
//从网站获取格言axios.get(https://v1.hitokoto.cn/?cfencodetext).then((data){//将数据插入数组mottoList.value.push(data.data);},(error){alert(出错了好小子 error)});
};
//同样可以调用生命周期函数
onMounted((){console.log(我是生命周期函数我被挂在后函数调用了)});
return {mottoList,mottoAddOne}
}numAdd:
import {ref} from vue;
//hooks中的ts文件也可以调用vue的生命周期函数
export default function(){
let numNowref(0);
//方法
function numAddOne(){numNow.value 1;
}
return {numNow,numAddOne}
}
文件中使用Person.vue)
import mottoAdd from ../hooks/mottoAdd;
import numAdd from ../hooks/numAdd;// 使用let {numNow,numAddOne} numAdd();let {mottoList,mottoAddOne} mottoAdd();
六、路由的使用
一创建路由需要的路由组件放在views文件夹中 二创建路由器在router文件夹中
import Index from ../views/Index.vue;
import News from ../views/News.vue;
import Play from ../views/Play.vue;
//引入创建router的函数创建路由器
import { createWebHashHistory,createRouter } from vue-router;
let routerFirst createRouter({history:createWebHashHistory(),routes:[{ name:xinwen,path:/news,component:News},{name:shouye,path:/,component:Index},{name:yule,path:/play,component:Play}]
})
export default routerFirst;
三在main.ts中使用路由
//引入
import routerFirst from ./router/index;
import {createApp} from vue;
import App from ./App.vue;
let app createApp(App);
//使用
app.use(routerFirst);
app.mount(#app);
四声明route-link和route-view div idnavDiv!-- 用来跳转到指定路由 --router-link to/ active-classactive首页/router-linkrouter-link to/news active-classactive新闻/router-linkrouter-link to/play active-classactive娱乐/router-link/div!-- 声明路由组件出现的位置 --router-view/router-view
七、路由相关知识
一query传参
父级组件内发送参数
router-link :to{path:/news,query:{oneData:若非群玉山头见,twoData:会向瑶台月下逢}} active-classactive新闻/router-link
路由组件内接收参数
//第一步引入useRouter函数
import {useRoute} from vue-router//第二步创建Route对象并获取对应querylet route useRoute();let oneData route.query.oneData;let twoData route.query.twoData;二params传参
在路由配置中定义传参参数名
{ name:xinwen,//?表示该属性可有可与path:/news/:oneData/:twoData/threeData?,//此行component:News},
组件接收参数
let oneData route.params.oneData;
let twoData route.params.twoData;
三props传参
router配置中 { name:xinwen,path:/news/:oneData/:twoData,component:News,props:true //开启后路径中的参数被作为props参数传入}
接收 defineProps([oneData,twoData]);
四自定义传递参数
router配置中
props(route){return route.query;}
Person组件中
router-link :to{path:/news/若非群玉山头见/会向瑶台月下逢,query:{oneData:云想衣裳花想容,twoData:春风拂槛露华浓}} active-classactive新闻/router-link
八、编程式路由导航
标签
button clicktoNews新闻/buttonscript
import {useRouter} from vue-router;let router useRouter();
function toNews(){router.push({path:/new,query:{oneData:昨夜雨疏风骤,twoData:浓睡不消残酒}});}
小点redirect重定向到新的路径
九、状态管理
一对比
Vue2使用vuex进行集中式状态管理Vue3使用pinia进行集中式状态管理
共同点是当有数据是全局共享的时候就要用到集中式状态管理来共同操纵共享的数据。
二使用
安装
sudo npm i pinia
引入
//引入集中式状态管理库pinia
import {createPinia} from pinia;
应用main.js)
//创建库
let pinia createPinia();
//使用pinia库
app.use(pinia);
模块化声明store创建store文件夹/创建useXXX.ts文件
模块化要求store命名都为usexxx.ts
//引入pinia中store选项
import {defineStore} from pinia;
//调用
//第一参数为唯一固定id号,命名必须为useXXX这是规定哦
export const useStore defineStore(useNum,{state(){return{myNum: 0 }//保存在集中状态管理中的数据。},actions:{//该参数是调用时传入滴,注意使用普通函数因要调用thiscutMyNumFun(numMid:number){this.$state.myNum - numMid;}},/* getters 中定义的函数都可以直接在store中调用类似于计算属性*/getters:{tenNum(state){return state.myNum * 10;}}
});函数式写法
export const useStore defineStore(useNum,(){let myNum ref(0); function cutMyNumFun(numMid:number){myNum.value - numMid;}/* getters 中定义的函数都可以直接在store中调用类似于计算属性*/let tenNum myNum.value * 10;return {tenNum,myNum,cutMyNumFun};
});
引入并使用
//引入storeToRefs让store解构出的属性同样是响应式滴
import {storeToRefs} from pinia;
//引入store
import {useStore} from ../store/numStore;
//产生store
let useNumStore useStore();
let myNumMid ref(0);//此数据用作临时中转下面用到这里不用关注
let {myNum,tenNum} storeToRefs(useNumStore);
这样公用数据就被我们响应式引入到组件中了
在下面结构中使用和更改数据
结构
div idnumAddh3现在数字是{{ myNum }}/h3h3该数字的十倍是{{ tenNum }}/h3!-- myNum需要集中管理另一组件也需要使用 --n:select v-modelmyNumMidoption :value11/optionoption :value22/optionoption :value33/optionoption :value44/option/selectbutton clickaddNum点我为数字加n/buttonbutton clickcutNum点我为数字减n/button/divscript
//方法逻辑
function addNum(){/* 修改数据方法一直接通过store接触到myNumstore中的myNum也是ref响应式但因为其在对象中所以会自动解包不用.value*/useNumStore.myNum myNumMid.value;
}
function cutNum(){/*数据修改方法二通过state接触到myNum */// useNumStore.$state.myNum - myNumMid.value/*数据修改方法三在store配置中增加actions然后调用actions中相关方法 这种方式一般用在逻辑比较复杂的时候*/useNumStore.cutMyNumFun(myNumMid.value);
}
三store.$subscribe订阅
当咱创建的store对象中state数据有变化时该函数会被调用
useNumStore.$subscribe((mutations,state){//state中的数据发生了变化console.log(数据发生了变化 state.myNum \n );console.dir(mutations)
}); state变化后的数据。 mutations事件对象、target.newValue、target.oldValue 十、组件间通信
一父传子、子传父自定义事件
父传子 父组件
Person refsonComponent :fatherData{name:路飞,age:23,text:hhhh嘿嘿}/Person !--子组件--
子组件
h2从父组件中获得的数据{{ fatherData.name }}/h2defineProps([fatherData]);
子传父
父组件结构
h2从子组件获取的数据:{{ mySonData.name }}/h2script
let mySonData:any ref({});
function getSonData(value:object){mySonData.value value
}子组件结构button clickgive送数据/buttonscript
//接收到父组件传递的自定义事件可以多个
let emits defineEmits([get]);
//根据指定自定义事件执行后面参数是传递的参数
function give(){emits(get,{name:儿子,age:33})
}二引入外部库mitt实现数据传递
引入npm i mitt
创建utils文件夹创建emittev.ts并导出实例
import mitt from mitt;
export const bus mitt();
//四个方法all所有数据、emit执行事件、off解绑事件、on绑定事件。
数据获取方
import {bus} from ./utils/emittev;
let mySonData:any ref(0);bus.on(get,(value:any){ mySonData.value value;})
数据提供方
bus.emit(get,{name:儿子,age:24})
三利用$attrs实现爷孙数据传递。
注明当父组件给子组件传递数据时子组件若不使用defineProps接收则在子组件的$attrs中利用此点实现爷传孙
传递数据时 :name小李 :age23 等同于 v-bind{name:小李 :age:23 }
爷
Person v-bind{name:我是你爸爸的爸爸,say:好好生活未来会更好}/Person
儿子
PersonSon v-bind$attrs/PersonSon
孙子h2这是从爷爷那里获取的数据{{ name say }}/h2defineProps([name,say]);
四provide、injectvue提供
主要用于隔代数据传递该方式不需要中间组件参与有利于降低逻辑复杂性
提供方结构爷
div ididContainPerson /Personh2这是传递给孙子的数据{{ giveSonData }}/h2button clickchangeDataInGrd点我改变爷爷的数据/button/div
供方js
import {ref,provide} from vue;
let giveSonData ref({name:韩少功,age:34,dream:成为一个大作家})
//将数据给出去。
provide(giveDataToMySon,giveSonData);
function changeDataInGrd(){
giveSonData.value.dream 看看我是不是响应式的;}provide(changeGrdData,changeDataInGrd);
接收方结构
div idpersonDivh2接收到来自爷爷的数据{{ dataFromGrd }}/h2button clickchangeData改变来自爷爷的数据/button/div
接收方js
import {ref,inject,toRefs} from vue//接收,第二个参数是默认值当该标签数据不存在时就使用默认值let dataFromGrd inject(giveDataToMySon,{name:孤胆英雄,dream:成为一个真正自立自强的人});//检验是否是响应式数据let changeData inject(changeGrdData,(){});
以上方式数据通过爷组件来修改所以数据都是响应式的
要想是响应式数据要是对象要么是一个响应对象的整体refreative包裹若是响应式对象中某个具体的值则在接收方不会是响应式
十一、插槽的使用跟vue无二致不详细解释
插槽就是当有同样的形式需要插入不同的数据可以利用插槽省写组件仅用一个组件来装入不同数据。
一默认插槽
首先需要声明一个通用的插槽形式
templatediv idslotDiv!-- 标明默认插槽的位置 --slot/slot /div
/templatescript langts
export default {name:SlotNews
}
/script
script setup langts/scriptstyle/style
引入并使用三次
div idpersonContainSlotNewsli v-for(say,index) in loveSaysList :keyindex{{ say }}/li/SlotNewsSlotNewsh2{{ name }}/h2/SlotNewsSlotNewsh4{{ people }}/h4/SlotNews
button clickgetNewLoveSays获取情话/button
/div
//数据一
let loveSaysList:any ref([]);
async function getNewLoveSays(){axios.get(https://api.uomg.com/api/rand.qinghua?formatjson).then((dataFrom){let {data:{content}} dataFrom;loveSaysList.value.push(content);},(error){console.log(出现错误 error)})
}
//数据二
let name ref(少年)
//数据三
let people ref({name:陈大炮,age: 23
})
默认插槽就是你在组件标签中加入的元素都会被添加到slot标签的位置。
二命名插槽
由名知意当组件标签中要插入多个内容且插入位置不同时需要多个slot标签来表标识slot标签使用 name属性标识。
div idslotDiv!-- 标明默认插槽的位置 --slot nameone/slothrslot nametwo/slot/div
父组件中使用v-slot或者#插槽名将元素插入指定位置注意只能在template标签中使用
SlotNewstemplate #twoli v-for(say,index) in loveSaysList :keyindex {{ say }}/li/templatetemplate #oneh2哈哈哈哈/h2/template/SlotNewsSlotNewstemplate #oneh2{{ name }}/h2/template/SlotNews
三作用域插槽
当数据在子组件中父组件需要获取时就是作用域插槽的用武之地。
子组件通过slot标签将数据传递到父组件。
slot nameone :trueSay我爱你像火焰一般炽烈/slot
父组件接收
SlotNews!--注意结束数据的格式--template #onetrueSayh2{{ trueSay.trueSay }}/h2/template/SlotNews
十二、其他API
一shallowRef、shallowReactive
只建立第一层数据的响应式更深层次不具有响应式在接收返回对象类型较大且有特殊要求时能够提高效率
二readonly shallowReadonly toRaw martRaw
给响应式数据加上只读限制方式他人使用误修改
let name ref(少年);
let nameReadOnly readonly(name);
//报错
nameReadOnly.value dksjl ;
let people ref({name:陈大炮,age: 23,lover:{name:枪炮,age:45}
});let peopleShallowReadOnly shallowReadonly(people);peopleShallowReadOnly.value.lover.age 66;//报错,只读属性peopleShallowReadOnly.value {};
toRaw从一个响应式数据中抽取其原始数据 markRaw 标记一个对象使其永远无法成为响应式数据
三customRef(自定义响应式数据
let name 意气风发;
let nameRef customRef((track,trigger){return{get(){track();//一旦数据被修改就会调用该函数return name;},//当数据被修改时调用传入修改后的值set(newValue){console.log(数据被修改了修改后的数据是 newValue);name newValue *;trigger();//告诉get数据被修改了。}
}
});function changeName(){nameRef.value 无敌好吧}结构
h2{{ nameRef }}/h2
button clickchangeName修改name/button
四teleport
Teleport tobody!--将被包裹的元素传送到指定元素中但是真实父子关系及数据处理逻辑不变--/Teleport
对于一些特殊样式设计有很大作用如图片使用filter属性导致fix失效定位无法以视口为基准这时就可以用该组件将其传入body中进行fix定位。