(摘) Vue快速学习

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

上篇Node.js的光速入门{:target="_blank"}是为了学习VUE,而学VUE其实是为了学习UNIApp。嗯,有点套娃的感觉。或许还要返回去学学TypeScript。
其实2021就有关于uve3的学习{:target="_blank"},这里算是复习,没咋用就会忘。这次结合视频讲座快速的再入门。

官网https://cn.vuejs.org/

基础项目

创建:npm init vue@latest
安装相关:npm install
运行:npm run dev

或者使用cnpm: 安装cnpm:npm install -g cnpm –registry=https://registry.npm.taobao.org

净身

把不必要的删除掉,主要就是src目录app.vue和main.js,assets放一些静态文件,package.json为node.js配置,vite.config.js为vue配置

App.vue文件

<template>
  <p>{{ msg }}</p>
</template>

<script>
  export default{
    data(){
      return {
        msg: "啥东东"
      }
    }
  }
</script>

内为html,内为脚本,实际还有定义样式
中的data()部份用于定义变量供使用,看起来与golang的模板类似

在以下示例中 v-html将使用原始标签来显示变量内容

<template>
  <p>{{ msg }}</p>
  <p>{{ ok?'好':"不好" }}</p>
  <p>{{ msg.split('').reverse().join("") }}</p>
  <p v-html="rawHtml"></p>
</template>

<script>
  export default{
    data(){
      return {
        msg: "啥东东",
        ok: true,
        rawHtml:"<a href='https://i.scwy.net'>我的博客</a>"
      }
    }
  }
</script>

属性绑定

// App.vue
<template>
  <HelloWorld></HelloWorld>
</template>

<script setup>
  import HelloWorld from "./components/HelloWorld.vue"
</script>


// HelloWorld.vue
<template>
    <div v-bind:class="msg" v-bind:id="dynamicId">{{ msg }}</div>
</template>

<script>
    export default{
        data(){
            return {
                msg: "active",
                dynamicId: "appID"
            }
        }
    }
</script>

这里有两点:v-bind 即属性绑定。另外 app.vue中script setup有所不同。
可以简写如下:{{ msg }}, 即省略v-bind

动态绑定多个值:

<template>
    <div v-bind="objAttrs">绑定多值</div>
</template>

<script>
    export default{
        data(){
            return {
                objAttrs: {
                    id: "abc",
                    class: "def"
                }
            }
        }
    }
</script>

这样,在前端将看到 绑定多值 ,即自动将id和class绑定到div上。也可以绑定自定义属性。

条件渲染

v-if v-else v-show v-else-if

<div v-if="flag">123</div>
<div v-else>321</div>

列表渲染

v-for

<template>
    <p v-for="item in names">{{ item }}</p>
</template>

<script>
    export default{
        data(){
            return {
                names: ["你","我","他"]
            }
        }
    }
</script>


<template>
    <p v-for="item in names">{{ item.name }} - {{ item.id}}</p>
</template>

<script>
    export default{
        data(){
            return {
                names: [
                    {name:"你",id:1},
                    {name:"我",id:2},
                    {name:"他",id:3},
                ]
            }
        }
    }
</script>

//或者
    <div v-for="item in names">
        <p>{{ item.name }}</p>
    </div>

也支持 item of names 将 in 改为 of

遍历变量属性:

 <p v-for="val,key,index in userInfo">{{index}}. {{ val }} {{ key }}</p>

                userInfo: {
                    id: 123,
                    name: "abc",
                    age: 23
                }

事件处理

v-on 或 @

<template>
  <button @click="addCount1">加1</button>
  <button @click="addCount('ok',$event)">加1</button>
  <p>Count:{{ count }}</p>
</template>
<script>
  export default {
    data() {
      return {
        count: 0
      }
    },
    methods:{
      addCount(msg,e){
        this.count+=1
        console.log(e);
        console.log(msg);
      },
      addCount(e){
        this.count+=1
        console.log(e);
        console.log(e.target.innerHTML);
      }
    }
 }
</script>

事件修饰符

.stop阻止默认事件 .prevent阻止事件冒泡 .once只触发一次 .enter回车键触发

// 在函数中阻止默认响应。
<a href="https://i.scwy.net" @click="clickHandle">我的博客</a>

      clickHandle(e){
        e.preventDefault();
        console.log("点");
      }

// 更简单的,使用事件修饰符
 <a href="https://i.scwy.net" @click.prevent="clickHandle">我的博客</a>

数组变化侦测

push() pop() shift() unshift() splice() sort() reverse() 使用它将直接影响UI显示的内容
fiter() concat() slice() 影响变量,但不影响引用变量的UI

计算属性

不同于函数(方法),计算属性仅在其值改变时,才进行计算。而前者会每次都运算。

<p>{{ Total }}</p>

// 在script中添加
computed:{
    Total() {
        return this.count + 100;
    }
}

Class绑定

由后方的变量决定样式是否使用

<div :class="{ 'active': isActive, 'error': isError}">这是文字</div>

    data() {
      return {
        count: 0,
        isActive: true,
        isError: false,
      }
    },


<style>
  .active {
    font-size: 20px;
  }

  .error {
    color: red;
  }
</style>

多个绑定,与上面的效果一样。

<div :class="classObject">Class绑定</div>
<div :class="[arrActive,arrHasError]"></div>
    data() {
      return {
        arrActive: "active",
        arrHasError: "error",
        classObject:{
          'activev':true,
          'error':true,
        }
      }
    },

Style绑定

<template>
  <div :style="{color: activeColor, fontSize: fontSize + 'px'}">123</div>
  <div :style="styleObject">356</div>
</template>
<script>
  export default {
    data() {
      return {
        activeColor: 'red',
        fontSize: 30,
        styleObject:{
          color: 'red',
          fontSize: '30px',
          fontWeight: 800,
        }
      }
    }
  }
</script>

侦听器

// 在script中添加 watch

<script>
    data(){
       return {
              message: "hello"
       }
    },
    watch: {
       // 监听message变量的变化,名称需与变量名一致。
       message(newValue,oldValue){

       }
    }
</script>

表单输入绑定

实时获取到message变量的内容到

<template>
  <p>{{ message }}</p>
  <form>
    <input type="text" v-model="message" />
  </form>
</template>
<script>
  export default {
    data() {
      return {
        message: 'hello'
      }
    }
  }
</script>
<template>
  <p>{{ message }}</p>
  <form>
    <input type="text" v-model="message" />
    <input type="checkbox" id="checkbox" v-model="checked" />
    <label for="checkbox">{{ checked ? "是":"否" }}</label>
  </form>
</template>
<script>
  export default {
    data() {
      return {
        message: 'hello',
        checked: false,
      }
    }
  }
</script>

修饰符

.lazy懒获取(确定或失去焦点时获取值) .number只获取数字(我测试却不只是数据?) .trim 去空格

模板引用

DOM获取,通过特殊的ref,然后就会暴露在this.$ref

<template>
  <div ref="cont">{{ content }}</div>
  <button @click="getEleHandle">获取</button>
</template>
<script>
  export default {
    data() {
      return {
        content: 'hello'
      }
    },
    methods:{
      getEleHandle(){
        console.log(this.$refs.cont);   // 这里就获取到了DOM对象
      }
    }
  }
</script>

组件

这里的scoped表示样式仅对组件内有效

<style scoped>
</style>
<template>
    <!-- 第二步:显示 -->
    <MyComp />
</template>

<script>
// 第一步:引入组件
import MyComp from './MyComponent.vue'
export default {
      // 第二步:注入组件
      components: {
          MyComp
      }
}
</script>

组件

全局注册/局部注册

全局注册即在main.js中注册(打包时必包含)

import { createApp } from 'vue'
import App from './App.vue'

// 这里引用
import Header from "./pages/Header.vue"

// 注册
App.components("Header",Header)

createApp(App).mount('#app')

组件传递数据 Props

// Child.vue

<template>
    <p>子组件</p>
    <p>{{ title }}</p>
</template>

<script>
    export default{
        props:["title"]  // 这里定义了可以传输的数据,注意格式为数组 
    }
</script>


// App.vue

<template>
    <Child title="调用传递" />
</template>
<script>
  import Child from "./components/Child.vue"
  export default {
    components:{
      Child
    }
  }
</script>

动态传递值,即将传递的值指向变量

// 仅App.vue调用改为如下,即将title值指向了message
<template>
    <Child :title="message" />
</template>
<script>
  import Child from "./components/Child.vue"
  export default {
    data() {
      return {
        message: "传数据"
      }
    },
    components:{
      Child
    }
  }
</script>

pros校验

在被调用组件中设置参数的类型

  props:{
      title: {
          type: String
      }
  }

可以接受多种类型

  props:{
      title: {
          type: [String,Number,Object]
      }
  }

默认值

  props:{
      title: {
          type: Number,
          default: 0   // 指定默认值
      }
  }

如果类型为数组或对象,必须通过工厂函数设置默认

  props: {
       name: {
            type: Array,
            default() {
                    return ["空"]
            }
       }
  }

必选项

   props: {
        title: {
             type: Number,
             required: true // 必选
        }
   }

注意:禁止修改调用传过来的值,只读

组件事件

组件传递数据

$emit触发自定义事件

// App.vue

<template>
    <Child :title="message" @someEvent="getHandle" />   <!--设置自定义事件-->
</template>
<script>
  import Child from "./components/Child.vue"
  export default {
    data() {
      return {
        message: "传数据"
      }
    },
    methods:{
      getHandle(data){   // 接收自定义事件的数据data
        console.log("触发事件 ",data);
      }
    },
    components:{
      Child
    }
  }
</script>


// Child.vue

<template>
    <p>组件事件</p>
    <p>{{ title }}</p>
    <button @click="clickEvent">传递数据</button>
</template>

<script>
    export default{
        data(){
            return {
            }
        },
        props:["title"],
        methods:{
            clickEvent(){
                this.$emit("someEvent","数据内容") // 自定义事件someEvent,并传递数据
            }
        }
    }
</script>

配合v-model使用

在两个组件之间获取数据

// Main.vue
<template>
     <p>{{ search }}</p>
     <SearchComponent @searchEvent="getSearch" />
</template>
<script>
     import SearchComponent from "./SearchComponent.vue">
     export default {
            data() {
                  return{
                     search: ""
                  }
            },
            components:{
                  SearchComponent
            },
            methods:{
                  getSearch(data){  // 获取子组件传来的值
                      this.search = data;
                  }
            }
     }
</script>



// SearchComponent.vue
<template>
       <input type="text" v-model="search">
</template>

<script>
     export default {
          data() {
                return {
                       search: ""
                }
          },
          watch:{
                search(newValue,oldValue){   // 通过变量值的监听,将新值上传
                      this.$emit("searchEvent",newValue)
                }
          }
     }
</script>

透传 Attributes

将属性传给组件的唯一根元素 class style id

export default {
    inheritAttrs: false // 禁止属性继承
}

插槽 Slots

// SlotsBase.vue

<template>
      <h3>示例</h3>
      <slot></slot>   也可以在中间设置一个默认值
</template>


// App.vue

<template>
    <SlotsBase>
            <h3>abc</h3>  <!--将这里的内容显示到slot组件中-->
    </SlotsBase>
</template>
<script>
     import SlotsBase from "..."
     export default {
          components: {
              SlotsBase
          }
     }
</scritp>

多个插槽(具名插槽)

// Solts.vue

<template>
    <slot name="header">插槽1</slot>
    <hr>
    <slot name="main">插槽2</slot>
</template>
</template>


// App.vue

<SlotsBase>
    <template v-slot:header>
         <h3>123</h3>
    </template>
    <template v-slot:main>
         <h4>abc</h4>
    </template>
</SlotsBase>

可以简写:

<template #header>

插槽中的数据传递
将组件中的数据传到调用者,再由调用者组合,形成插槽数据,然后组件进行接收。达到共用调用者和组件数据的目的。

// App.vue
<template>
  <SlotsAttr v-slot="slotProps">
       <h3> {{ message }} - {{ slotProps.msg }}</h3>
  </SlotsAttr>

</template>
<script>
   import ...
   components: { ... }
</script>

// SlotsAttr.vue
<template>
    <slot :msg="childMessage"></slot>
</template>
<script>
    export deault {
       data() {
           return {
                childMessage: "asdfasd"
           }
       }
    }
</script>

具名插槽

<template #header="slotProps">

生命周期

创建期:beforeCreate created
挂载期:beforeMounte mounted
更新期:beforeUpdate updated
销毁期:beforeUnmount unmounted

动态组件

根据变量的值来确定显示哪个组件

<template>
   <component:is="tabComponent"></component>
</template>

<script>
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"
export default {
   data()(
     return {
       tabComponent: "ComponentA"
     }
   },
   components:{
       ComponentA,
       ComponentB
   }
}
</script>

组件保持存活

<template>
   <keep-alive>
        <component :is="tabComponent"></component>
   </keep-alive>    
</template>
<script>
  export default {
     data(){
     },
   
  }
</script>

异步组件

需要时再加载,可达到优化项目

<script>
    import { defineAsyncComponent } from 'vue'
    const AsyncComponentB = defineAsyncComponent(() =>
          import('./ComponentB.vue')
    )
</script>

信赖注入

即多级数据的向下传送

// 父级发送
<script>
    export default{
         provide:{
             message: "父级数据"
         },
    }  
</script>


// 孙级接收
<script>
    export default {
         inject: ["message"]
    }
</script>

// 或者父级发送
export default {
    data() {
        return {
            message: 'ok'
        }
    },
    provide() {
         return {
             message: this.message
         }
    }
}

在main.js可以定义全局数据:

...
const app = createApp(App)
app.provide("globalData","全局数据")
app.mount('#app')
...

然后在各组件中引用

export default {
      inject: ['globalData'],
}

Vue应用

应用实例

import { createApp } from 'vue'

const app = createApp({
   /* 根组件选项 */
})

根组件

import App from './App.vue'
const app = creaetApp(App)

挂载应用

app.mount('#app')

这里,vue会找根目录下index.html的id为app的控件,所有vue的渲染将在其下。


补充

通过 CDN 使用 Vue

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>