需要@vue/cli版本在4.5.0以上
# 查看版本
vue --version
# 安装或升级@vue/cli
npm install -g @vue/cli
# 创建vue项目
vue create vue-test
# 启动
cd vue_test
npm run serve
vite --> 新一代前端构建工具
优势
# 安装vite
npm install -g create-vite-app
# 创建工程
npm init vite-app <project-name> # 我忘记安装vite了,这里可以根据提示信息安装
Need to install the following packages:
create-vite-app
Ok to proceed? (y)
Done. Now run:
cd vue_test
npm install (or `yarn`)
npm run dev (or `yarn dev`)
# 进入工程目录
cd <project-name>
# 安装依赖
# cnpm install; 会快很多
npm install
# 运行
npm run dev
Dev server running at:
> Network: http://192.168.20.1:3000/
> Network: http://192.168.10.1:3000/
> Network: http://192.168.43.237:3000/
> Local: http://localhost:3000/
先使用vue-cli,之后在学vite相关知识点
main.js
/*
引入了createApp的工厂函数,不使用new创建可以直接调用
import Vue from 'vue'; vue2
*/
import {
createApp } from 'vue'
import App from './App.vue'
/*
new Vue({
render: h => h(App)
}).$mount('#app')
*/
//createApp(App).mount('#app')可以拆成两个
//创建应用实例对象app,类似vm,但app更轻
const app = createApp(App)
//挂载
app.mount('#app')
vue3组件中的模板结构可以没有根标签
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
组合式 API,使用前先引用。基本都是函数,参数也是函数。
根据需要引用的不同的封装好了的函数
vue2 : Option API 配置式的API
vue3: Composition API 组合式API
vue2的不足:当修改或新增需求,需要分别在data,methods,computed里修改
vue3:可以更加优雅的组织代码和函数,让相关功能的代码更加有序的组织在一起。
是什么?
Vue3.0中一个新的配置项,值为一个函数
组件中使用的数据、方法、生命周期钩子等,都要配在setup中
setup函数的两种返回值
1.若返回一个对象,则对象中的属性、方法,在模板中均可直接使用 ★
2.若返回一个渲染函数,则可以自定义渲染内容(了解)
补充:setup不能是async函数,因为返回值不是return对象了,而是promise,模板看不见promise对象中的属性
//返回对象(常用)
<template>
{
{
name}}
{
{
say()}}
</template>
<script>
export default {
name: 'App',
setup() {
//这里定义的数据不是响应式数据
//数据
let name="ranan";
//方法
function say() {
console.log(`hello${
name}`);
}
return {
name,say}
}
}
</script>
//返回一个渲染函数
<template></template>
<script>
import {
h} from 'vue' //createElement函数
export default {
name: 'App',
setup() {
//渲染函数要把h函数调用的返回值返回
//return ()=>{return h('h1','ranan')}
return ()=> h('h1','ranan')
}
}
</script>
vue2和vue3配置混用–最好不要混用!
ref函数:给数据加工使其具有响应式,返回值是一个RefImpl引用对象(引用实现的实例对象),也叫做Ref对象
ref响应式的原理是使用数据劫持(第一层): defineProperty中的getter,setter
RefImpl:reference引用的implement实现
数据的获取使用属性名.value获取,但是模板中直接使用属性名,模板中会自动.value
<template>
{
{
a}}
</template>
import {
ref} from ’vue‘;
<script>
export default {
name: 'App',
setup() {
//这里定义的数据不是响应式数据
//数据
let name=ref("ranan");
function changeName(){
name.value = "xxx"
}
}
}
</script>
job本身还是RefImpl引用对象,job.value进行加工返回Proxy代理对象A,此代理对象代理了源对象,通过对代理对象的操作间接操作源对象
将对象里的属性直接抛出时,响应式会失效,在模板中修改该属性是不会触发重新渲染。
原因是:暴露出去的数据是普通对象
setup() {
let job = ref({
//!!!!!!!!!!!!!!!!!!!重要
//ref本身是通过getter,setter有响应式的,如果抛出job,替换job是有响应式
//job.value是通过proxy进行响应式的
type:'学生',
salary:'0'
})
console.log(job.value);
/*
Proxy{
"type": "学生",
"salary": "0"
}
*/
return {
//这里相当于抛出普通值0
job.value.salary; //模板中修改该属性,不会引起响应式
}
}
ref函数的作用:定义一个响应式的数据
语法:const xxx = ref (initValue)
xxx.value
{
{属性名}}
Object.defineProperty()
的get与set函数reactive
函数作用:定义一个对象类型的响应式数据
语法:const 代理对象 = reactive(源对象)
接受一个对象(或数组),返回一个Proxy的实例对象
说明: reactive定义的响应式数据是深层次的,内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作
import {
reactive} from 'vue';
export default {
name: 'App',
setup() {
let job = reactive({
type:'学生',
salary:'0'
})
console.log(job);
/*
Proxy {type: '学生', salary: '0'}
*/
}
}
reactive | ref | |
---|---|---|
定义数据 | 对象类型数据 | 基本类型数据 如果定义对象,.value会借住reactive将对象转为代理对象 |
原理 | Proxy实现响应式(数据劫持) 通过Reflect操作源对象内部的属性 |
通过Object.defineProperty()的get和set来实现响应式(数据劫持) |
使用 | 不需要使用.value | 操作数据需要.value,模板中读取不需要.value |
对象类型:通过Object.defineProperty()
对属性的读取、修改进行拦击-数据劫持
数组类型:通过重写更新数组的一系列方法来实现拦截的
存在的问题
vm.$set(obj,key.val)
/vm.$delete(obj,key)
新增属性/删除属性vm.$set(arr,index.value)
,调用数组的splice方法实现原理
//通过修改代理对象p来简介操作源对象person
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${
propName}属性`)
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${
propName}属性,我要去更新界面了!`)
Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${
propName}属性,我要去更新界面了!`)
return Reflect.deleteProperty(target,propName)
}
})
计算属性不是一个对象,而是一个函数
import {
computed} from 'vue'
setup(){
//计算属性-简写内部是函数形式,只符合被读取的情况
let fullName = computed(()=>{
return person
})
//计算属性-完整写法
let fullName = computed({
get(){
},
set(val){
}
})
}
watch的参数
1.监视的数据
2.该数据绑定的回调函数
3.vue2的配置参数
import {
ref,reacitve,computed} from 'vue'
setup(){
let sum = ref(0)
let msg= ref("hello")
let person= reactive({
name:"ranna",
age:18,
job:{
j1:{
salary:20
}
}
})
//情况1:监视ref所定义的响应式数据,第三个参数是类似vue2的配置参数
watch(sum,(newvalue,oldValue)=>{
},{
immediate:true,deep:true})
//情况2:监视ref所定义的多个响应式数据
watch([sum,msg],(newvalue,oldValue)=>{
//此时newvalue和oldValue都是数组,里面的顺序和第一个参数的顺序一致
})
//情况3:监视reacitve,当person里面的属性发生变化时可以检测到,常用
watch(person,(newValue,oldValue)=>{
//!!!!!!此时无法正确的获取oldValue,oldValue和newValue的值一样了
})
//情况4:监视reactive定义的响应式数据中的某个属性
watch(()=>person.name,(newValue,oldValue)=>{
//此时可以获取到oldValue
})
//情况5:监视reactive定义的响应式数据中的某些属性
//()=> [person.name,person.age]也可以
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
//person.name和person.age是基本数据类型,此时可以获取到oldValue
})
//特殊情况:监视reactive定义的响应式数据中的某个属性时,修改job属性里面的salary时需要开启深拷贝,deep有效
watch(()=>person.job,(newValue,oldValue)=>{
//person.job是对象,此时获取不到oldValue
}.{
deep:true})
return {
person}
}
**注意这里有坑!!! **
1.监视reacitve定义的响应式数据的全部属性时,当person里面的属性发生变化时可以检测到,此时无法正确的获取oldValue,oldValue和newValue的值一样了,因为对象里面的数据发生了改变,但是对象是一个地址,地址没有发生改变 --> 监视的是基本数据类型就可以获取到oldValue
2.监视reactive定义的响应式数据的全部属性时,强制开启了深度监视deep配置无效 --> 对于对象的第一层,深度监视强制开启,如果对象里面还有对象,那么deep配置生效需要手动配置
当ref的参数是对象时,ref对象采用的defineProperty,进行了一层的数据劫持,对比是否发生修改是比较的.value地址值,如果修改对象里面的数据是不会被发现修改了的
let sum = ref(0);
let person= reactive({
name:"ranna",
age:18,
job:{
j1:{
salary:20
}
}
})
//console.log(sum);//ref对象,ref.value值是基本类型
console.log(person);//ref对象,ref.value值是Proxy对象
//console.log(sum.value);//0
//这里监视时sum变量也就是ref对象,写成sum.value监视的是0这个值是不可以的
watch(sum,(newvalue,oldValue)=>{
});
//person是ref对象,ref对象采用的defineProperty,对比是否发生修改是比较的.value地址值,如果修改对象里面的数据是不会被发现修改了的
watch(person,(newvalue,oldValue)=>{
}); //无效
watch(person,(newvalue,oldValue)=>{
//有效,defineProperty只监视一层,类似vue2,开启深度监视就可以了
console.log(newvalue);
},{
deep:true})
watch(person.value,(newvalue,oldValue)=>{
//有效,这里的person.value = reacitve()函数返回的,也就是监视的是reacitve定义的对象
console.log(newvalue);
})
watchEffect函数有点像computed函数
//一上来就会执行
watchEffect(()=>{
})
vue2:beforeCreate
、created
、beforeMount
、mounted
、beforeDestroy
、destroyed
vus3:beforeCreate
、created
、beforeMount
、mounted
、beforeUnmount
、unmounted
写在setup函数外面按照vue2的配置项形式写
如果通过配置项的写法,setup()在beforeCreate()之前执行一次
export default{
name:'Demo',
setup(){
},
beforeCreate(){
},
created(){
},
//....
}
使用Composition组合式API形式在setup函数里使用生命周期钩子
beforeCreate
、created
钩子没有提供组合API的形式
执行顺序:相同的组合式API会先于配置项
import {
onMounted} from 'vue' //按需引用
export default{
name:'Demo',
setup(){
onBeforeMount(()=>{
})
}
}
**什么是hook? **
本质是一个函数,把setup函数中使用的Composition API进行了封装
将某个功能的js代码,封装在一个js文件里以函数形式暴露,一般将该js文件放在src/hooks目录下,以usexxx.js命名 --> 类似mixin mixin里面没有周期函数
组件需要使用的时候再引入该js文件
自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂
import {
需要的组合api函数如生命周期钩子等} from'vue'
function savaPoint(){
//实现鼠标打点相关的数据
//实现鼠标打点相关的方法
//实现鼠标打点相关的生命周期钩子
return 有用的东西
}
export default savaPoint;
作用: toRef函数创建一个ref对象,该ref对象的value值指向参数对象中的某个属性,返回ref对象的value值改变,参数对象中的该属性也会改变
说明: 本质是引用,与原始数据有关联
语法: const name=toRef(person,'name')
应用: 要将响应式对象中的某个属性单独提供给外部使用
<template>
{
{preson.name}}
{
{preson.age}}
{
{preson.job.j1.salary}}
</template>
<script>
import {
reactive} from 'vue'
export default{
name:'Demo',
setup(){
let person= reactive({
name:"ranan",
age:18,
job:{
j1:{
salary:20
}
}
})
return {
person}
}
}
</script>
需求:让模板中使用数据的代码更简单点
<template>
{
{name}}
{
{age}}
{
{salary}}
</template>
<script>
import {
reacitve} from 'vue'
export default{
name:'Demo',
setup(){
//,,,,
return{
//这样写的问题是没有响应式,这样相当于是将基本数据类型值进行赋值,修改name是不会引起person.name进行修改的
name:person.name,//name = “ranan”
age:person.age,
salart:person.job.j1.salary
}
}
}
</script>
错误写法:这样写的问题是没有响应式,这样相当于是将基本数据类型值进行赋值,修改name是不会引起person.name进行修改的
解决办法:toRef函数创建一个ref对象,该ref对象的value值指向参数对象中的某个属性,ref的value值改变,参数对象中的该属性也会改变,本质是引用,与原始数据有关联。
语法:const name=toRef(person,'name')
/*
{
"_object": {
"name": "ranan",
"age": 18,
"job": {
"j1": {
"salary": 20
}
}
},
"_key": "age",
"__v_isRef": true
value:(...)//读取的时候读的是person.age
}
*/
//const age= toRef(person,'age');
//return {
// age:age;
//}
return {
age:toRef(person,'age'); //本质是引用
age:ref(person.age);//相当于为18做了响应式返回了新ref对象,但是age的改变不会引起person.age的改变
}
说明: toRefs与toRef
功能一致,但可以批量创建多个ref对象,语法:toRefs(person)
返回一个和参数一致的对象,只不过属性的值都变成了ref对象的值
return{
...toRefs(person)
}
原来对象的响应式是通过Proxy实现的,之前获得person.age=值,现在获得person.age = ref对象
但是toRefs对于新增的属性不会生效,Ref使用的是defineProperty,对新增和删除没有反应。 --> 直接返回响应式对象本身即可
shallowReactive浅响应,只有对象的第一层有响应式
shallowRef对于对象类型更为严格,不处理对象类型的响应式
什么时候使用
let x = shallowRef({
y:0;
})
readonly:让一个响应式数据变为只读的(深只读),返回的还是proxy对象只是不能修改
shallowReadonly:让一个响应式数据变为只读的,只考虑对象的第一层
应用场景:不希望数据被修改时,不能修改数据
person = readonly(person); //person不可以修改
响应式数据 --> 普通数据
//当函数被调用时,p.age会+1,但是不会引起页面的改变,因为它是个普通对象
function showRawPerson(){
const p = toRaw(person);
p.age++;
}
function addCar(){
//person是响应式对象,利用Proxy,在上面添加属性会被监测到,person.car也是响应式的
let car = {
name:'奔驰',price:40};
person.car = markRaw(car)
}
作用:创建一个自定义的ref
需求:有两个输入框,在第一个输入框输入信息后,等1s后显示 --> 防抖的效果,只有最后一次触发延迟delay后执行回调,其余时候触发会重新开始计时
import {
ref,customRef} from 'vue'
export default {
name: 'App',
setup() {
//自定义一个ref——名为:myRef
function myRef(value,delay){
let timer
/*
cunstomeRef和Ref功能一致生成一个ref对象,但是内部逻辑自定义
参数是函数,该函数必须返回一个对象
*/
return customRef((track,trigger)=>{
return {
get(){
console.log(`有人从myRef这个容器中读取数据了,我把${
value}给他了`)
track() //通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
//有点类似收集依赖?
return value
},
set(newValue){
console.log(`有人把myRef这个容器中数据改为了:${
newValue}`)
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger() //通知Vue去重新解析模板,数据修改了重新get
//有点像set通知依赖
},delay)
},
}
})
}
// let keyWord = ref('hello') //使用Vue提供的ref
let keyWord = myRef('hello',500) //使用程序员自定义的ref
return {
keyWord}
}
}
作用:实现祖孙组件间通信
套路:父组件有一个provide
选项来提供数据,子组件有一个inject
选项来使用数据
具体写法
1.祖组件中
provide('给传入的数据起名',真实数据)
给自己的后代组件传递数据
setup(){
....
let car = reactive({
name:'奔驰',price:'40万'});
provide('car',car);
}
2.孙组件中
inject('接受的数据名')
后代组件接受祖先组件传来的值,返回值为该变量存储的数据,数据是Proxy对象
setup(props,context){
....
const car = inject('car');
return {
car};
....
}
reactive
创建的响应式代理readonly
创建的只读代理reactive
或者readonly
方法创建的代理说明
readonly()返回的还是proxy对象只是不能修改
好处:减少标签层级,减小内存占用
什么是Teleport
Teleport
能够将我们的组件html结构移动到指定位置的技术
/*将需要传送的结构用Teleport标签包裹*/
<teleport to="body">
<!--to="#ranan" 到id=ranan标签里面-->
</teleport>
Suspense组件作用:等待异步组件时渲染一些额外内容,让应用又更好的用户体验
compositionAPI defineAsyncComponent()
定义异步组件(动态组件/懒加载)
参数为函数,参数的函数需要有返回值
组件懒加载,先出来的组件可以先渲染 --> 性能优化解决首屏加载慢(白屏)的问题
//App组件中
<Child/>
// import Child from './components/Chile.vue' 静态引入
import {
defineAsyncComponent} from 'vue'
//动态引入、异步引入
const Child = defineAsyncComponent(()=>import('./components/Chile.vue'));
存在问题
Suspend内置组件不用引入直接使用,v-slot属性必须按要求写!
<template>
/*
内部使用插槽实现,此时已经准备好了两个插槽
插槽1 default插槽:Child组件展示的东西
插槽2 fallback插槽:当Child组件还没有加载好的时候展示的东西
*/
<Suspense v-slot:default>
<Child/>
</Suspense>
<Suspense v-slot:fallback> /*fallback退路*/
正在加载中....
</Suspense>
</template>
使用了异步组件和Suspense 组件后setup可以是async函数
const app = createApp(App)
app.mount('#app')
应用实例对象app,类似vm,但app更轻
vue3.x写法
.v-enter,
.v-leave-to{
}
.v-leave,
.v-enter-to{
}
vue3.x写法
.v-enter-from,
.v-leave-to{
}
.v-leave-from,
.v-enter-to{
}
v-on
的修饰符,同时不支持Vue.config.keyCodes.huiche=13
定义按键别名v-on.native
给组件绑定原生事件时,会以为是自定义事件<my-componet
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
子组件中声明自定义事件
export default{
emits:['close'] //没有指定click,则认为click是原生事件
}
移动互联网发展迅速,各种APP的开发都会推出多个版本(多终端),比如:iPhone版、iPad版、Android版。有些APP还会考虑覆盖到多个国家(国际化),比如:中文版、英文版、日文版、韩文版等。此外,针对不同渠道(流量来源)也会提供不同的版本(多渠道),比如:百度版、Google版、阿里版、腾讯版等。 对于应用提供方,希望入口只有一个:扫描二维码直接下载。怎样让这张二维码承载这么丰富的
在CAVIUM CN70xx板子,mips64内核,32位用户态上编译gdbserver 指南1、进入gdbserver目录 2、执行./configure –target=mips64-octeon-linux –host=mips64-octeon-linux 3、执行make CC=/opt/toolschain/cavium2/bin/mips64-octeon-linux-gnu-gc
Balsamiq Mockups是一种软件工程中快速原型的建立软件,可以做为与用户交互的一个界面草图,一旦客户认可可以做为美工开发HTML的原型使用。认识Balsamiq MockupBalsamiq Mockups是美国加利福利亚的Balsamiq工作室(2008年3月创建)推出的原型图绘制软件。于2008年6月发行了第一个版本。它的使命是帮助人们更好、更容易的设计软件产品。下面是Bal
####引言在学习了C语言基础之后 ,我们简单的了解了C语言编程的一些范式 , 了解了指针 , 结构体 , 联合体 , 函数 , 文件IO等等 。我们最终的目的是要学会NDK开发 , 而NDK开发就离不开我们的JNI技术 。下面 , 就来开始我们的JNI之旅吧 。####JNI的概念JNI全称 Java Native Interface , java本地化接口 , 可以通过JNI调用系统提供...
简介JVM堆外内存难排查但经常会出现问题,这可能是目前最全的JVM堆外内存排查思路。通过本文,你应该了解:pmap 命令gdb 命令perf 命令内存 RSS、VSZ的区别java NMT起因这几天遇到一个比较奇怪的问题,觉得有必要和大家分享一下。我们的一个服务,运行在docker上,在某个版本之后,占用的内存开始增长,直到docker分配的内存上限,但是并不会OOM。版本的更改如下:升级了基础...
最近,微软发布了Windows11系统,而在这之后,微软又针对office的UI界面进行大改。但是许多用户反馈,自己的office更新到最新的版本仍然没有新的UI。而今天小编就帮助用户通过修改注册表的形式来修改office新的UI界面吧!电脑自学网唯一官网:www.xitongzhijia.net操作方法:1、在桌面键一个空白的文本文档。2、在文本文档中输入以下代码:01Windows Regis...
mysql 恢复备份数据库的时候 提示:[Msg] 1418 - This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you might want to use the less safe log_bin_trust_f
媒体播放器原理视音频技术主要包含以下几点:封装技术,视频压缩编码技术以及音频压缩编码技术。如果考虑到网络传输的话,还包括流媒体协议技术 视频播放器播放一个互联网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码视音频,视音频同步。如果播放本地文件则不需要解协议,为以下几个步骤:解封装,解码视音频,视音频同步解协议的作用,就是将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频...
今天交叉编译libiconv,make的时候报错:libiconv.so: file not recognized: File format not recognizedcollect2: ld returned 1 exit status文件格式不对,查了一下sqlite3-shell.o的文件格式file libiconv.solibiconv.so: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped是x86
首页博客设计相册论坛关于#menu {padding:20px 20px 0 0}/* 固定导航栏位置 */#menu ul {float:right;list-style:none;margin:0px;}/* 添加float:right是的导航栏位于页面右侧 */#menu ul li {float:left;margin:0 10px;display:block;line-height:28...
最近小程序蛮火。 直入主题: 对于一张网络图片高度太高,而显示不全如何解决? 其实我一贯的观点是,所有的问题从api中都能够找到答案,只是有时候缺少耐心,而没有好好去读官方api,出现问题后着急的google、百度、github... 下面我们来看下api 怎么说的: image 图片。属性名 类型 默认值 说明 src Str...
jrhwpt01:/root# netstat -nap | grep nginxtcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 23886/nginx unix 3 [ ] STREAM CONNECTED