VUE3.0学习

1、CDN使用Vue

引入Vue.js

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

vite脚手架安装

先下载node.js并安装,在终端下使用npm安装vite

#安装脚手架
npm init vue@latest
#或
#vue-xu01是创建项目名称
npm init vite@latest vue-xu01 -- --template vue
#按y下一步
cd vue-xu01
#进入目录安装
npm install
#在目录下运行
npm run dev

Axios网络请求库使用

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

使用方法

axios.get("地址").then((response)=>{
//准确返回
},(err)=>{
//错误返回
})

2、创建第一个应用

每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例

import { createApp } from 'vue'

const app = createApp({
  /* 根组件选项 */
})
  const { createApp } = Vue
  
  createApp({
    data() {
      return {
        message: 'Hello Vue!',
        age:18
      }
    }
  }).mount('#app')

多个应用实例

const app1 = createApp({
  /* ... */
})
app1.mount('#container-1')

const app2 = createApp({
  /* ... */
})
app2.mount('#container-2')

3、模板语法

文本插值

<span>Message: {{ msg }}</span>

v-html网页化

<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

v-bind属性绑定

<div v-bind:id="dynamicId"></div>
<div :id="dynamicId"></div>

<div v-bind:class="dynamicId"></div>
<div :class="dynamicId"></div>

动态绑定多个值

data() {
  return {
    objectOfAttrs: {
      id: 'container',
      class: 'wrapper'
    }
  }
}
//html
<div v-bind="objectOfAttrs"></div>

动态参数

<!--
注意,参数表达式有一些约束,
attributeName可以设定id、class……
-->
<a v-bind:[attributeName]="url"> ... </a>

<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

v-on监听 DOM 事件

<a v-on:click="doSomething"> ... </a>

<!-- 简写 -->
<a @click="doSomething"> ... </a>

JavaScript 表达式

Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>

v-if判断真假

seen 的值的真假来显示 p元素

<p v-if="seen">Now you see me</p>

4、响应式

声明响应式状态

响应式对象其实是 JavaScript Proxy

export default {
  data() {
    return {
      count: 1
    }
  },

  // `mounted` 是生命周期钩子,之后我们会讲到
  mounted() {
    // `this` 指向当前组件实例
    console.log(this.count) // => 1

    // 数据属性也可以被更改
    this.count = 2
  }
}

声明方式

export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  mounted() {
    // 在其他方法或是生命周期中也可以调用方法
    this.increment()
  }
}

//html
<button @click="increment">{{ count }}</button>

DOM 更新时机

DOM 更新完成,你可以使用 nextTick() 这个全局 API

import { nextTick } from 'vue'

export default {
  methods: {
    increment() {
      this.count++
      nextTick(() => {
        // 访问更新后的 DOM
      })
    }
  }
}

深层响应性

export default {
  data() {
    return {
      obj: {
        nested: { count: 0 },
        arr: ['foo', 'bar']
      }
    }
  },
  methods: {
    mutateDeeply() {
      // 以下都会按照期望工作
      this.obj.nested.count++
      this.obj.arr.push('baz')
    }
  }
}

有状态方法

防抖的事件,限制项目中同一时间段内的连续click事件,防止前端触发多次事件

import { debounce } from 'lodash-es'

export default {
  methods: {
    // 使用 Lodash 的防抖函数
    click: debounce(function () {
      // ... 对点击的响应 ...
    }, 500)
  }
}

保持每个组件实例的防抖函数都彼此独立,我们可以改为在 created 生命周期钩子中创建这个预置防抖的函数:

export default {
  created() {
    // 每个实例都有了自己的预置防抖的处理函数
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // 最好是在组件卸载时
    // 清除掉防抖计时器
    this.debouncedClick.cancel()
  },
  methods: {
    click() {
      // ... 对点击的响应 ...
    }
  }
}

5、计算属性

computed:计算属性值会基于其响应式依赖被缓存

export default{
    data() {
      return {
        messages: 'Hello Vue!',
        age:18,
        isButtonDisabled:false,
      };
    },
    computed:{//计算属性,有缓存
        reverseMsg(){
            return this.messages.split('').reverse().join('')
        }
    },
    methods:{
        reverseMessage(){
            return this.messages.split('').reverse().join('')
        }
    },
}
//html
   <p>{{ messages.split('').reverse().join('') }}</p>
   <p>{{ reverseMsg }}computed计算属性</p>
   <p>{{ reverseMessage() }}methods响应式</p>

可写计算属性

get() 和 set()方法

export default{
    data() {
      return {
        messages: 'Hello Vue!',
        age:18,
        isButtonDisabled:false,
      };
    },
    computed:{//计算属性,有缓存
        reverseMsg:{
            get(){//get是默认方法
            return this.messages.split('').reverse().join('')
                },
            set(){
                //set设置后显示方式
            	},
        }
    },
    methods:{
        reverseMessage(){
            return this.messages.split('').reverse().join('')
        }
    },
}

6、watch侦听

export default {
  data() {
    return {
      message: "你好",
      age: 0,
      user: {
        name: "张三",
        age: 18,
        sex: "男",
      },
    };
  },
  methods: {},  
  watch: {
      message:function(newValue,oldValue){
       console.log(newValue);
       console.log(oldValue);
       //执行异步操作,或者复杂逻辑代码
       if(newValue.length<5 || newValue.length>10){
         console.log("输入框的内容不能小于5或者大于10");
       }
     }
    },
}

深层侦听器

export default {
  watch: {
    someObject: {
      handler(newValue, oldValue) {
        // 注意:在嵌套的变更中,
        // 只要没有替换对象本身,
        // 那么这里的 `newValue` 和 `oldValue` 相同
      },
      deep: true
    }
  }
}


watch: {
      "user.name": { //使用字符串的形式进行优化,只会单独监听对象中对应的属性
      handler(newValue) {
        console.log(newValue);
      },
      deep: true, //表示是否深度监听,侦听器会一层层的向下遍历,给对象每个属性都加上侦听器
    },
  },

即时回调的侦听器

watch: {
     message: {
      immediate: true, //初始化的时候即时调用函数
      handler: function (newValue) {
        console.log(newValue);
        if (newValue.length < 5 || newValue.length > 10) {
          console.log("输入框的内容不能小于5或者大于10");
        }
      },
    },
 },

7、Class 与 Style 绑定

对象语法

<div :class="{ active: isActive }"></div>

//或

data() {
  return {
    classObject: {
      active: true,
      'text-danger': false
    }
  }
},
computed: {
  classObjectCom() {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}
//html
<div :class="classObjectCom"></div>

数组语法

data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
}
//html
<div :class="[activeClass, errorClass]"></div>
//可以使用三元表达式
<div :class="[isActive ? activeClass : '', errorClass]"></div>

绑定内联样式

data() {
  return {
    activeColor: 'red',
    fontSize: 30
  }
}
//html
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

直接绑定一个样式对象通常是一个好主意,这样可以使模板更加简洁:

data() {
  return {
    styleObject: {
      color: 'red',
      fontSize: '13px'
    }
  }
}
//html
<div :style="styleObject"></div>

绑定数组

<div :style="[baseStyles, overridingStyles,{color: 'red'}]"></div>
//样式多值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
//数组仅会渲染浏览器支持的最后一个值。在这个示例中,在支持不需要特别前缀的浏览器中都会渲染为 display: flex

8、条件渲染

v-if

<h1 v-if="awesome">Vue is awesome!</h1>

v-else

<button @click="awesome = !awesome">Toggle</button>

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

v-else-if

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

template 上的 v-if最后渲染的结果并不会包含这个元素

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

9、列表渲染

v-for

data() {
  return {
    yy: ['张三','李四','老刘']
  }
}
//html
<li v-for="item in yy" :key="item">
  {{ item }}
</li>
//key唯一标识,方便它跟踪每个节点的身份,快速找到这个节点,减少渲染次数
data() {
  return {
    xx: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
//html
<li v-for="item in xx">
  {{ item.message }}
</li>
//也支持使用可选的第二个参数index表示当前项的位置索引
<li v-for="(item, index) in xx">
  {{ index }} - {{ item.message }}
</li>

v-for 与对象

data() {
  return {
    myObject: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
}
//html
<ul>
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>
//第二个参数表示属性名 (例如 key):
<li v-for="(value, key) in myObject">
  {{ key }}: {{ value }}
</li>
//第三个参数表示位置索引(例如 index):
<li v-for="(value, key, index) in myObject">
  {{ index }}. {{ key }}: {{ value }}
</li>

数组方法使用

this.list[5]='xx'
push()//给数组末尾添加元素
pop()//删除末尾元素
shift()//给数组的第一位进行删除
unshift()//给数组第一位添加元素
//splice本质是设定范围先删后插
splice()//删除元素、插入元素、替换元素:参数:1、开始位置下标 2、范围数量 3、插入元素
sort()//排序,默认按照字符串顺序对值从小到大进行排序
reverse()//反转元素顺序

使用案例

data() {
  return {
    yy: ['张三','李四','老刘']
  }
},
methods:{
    changList(){
        this.yy[0]='九妹'
        this.yy.push('老大','老二')
    },
},
//html
<button @click="changList">改变按钮</button>
<button @click="this.yy.pop()">删除末尾按钮</button>
<button @click="this.yy.shift()">第一位进行删除按钮</button>
<button @click="this.yy.unshift('我是第一位老大')">第一位添加数据</button>
//splice本质是设定范围先删后插
<button @click="this.yy.splice(2,4)">splice删除[2]-[5]元素</button>
<button @click="this.yy.splice(2,0,'我插一个','我不要插入')">splice插入[2]后面元素</button>
<button @click="this.yy.splice(2,2,'我替换1','我替换2')">splice替换[2]后面元素</button>
<button @click="this.yy.sort()">排序</button>
<button @click="this.yy.reverse()">反转</button>

<li v-for="item in yy" :key="item">
  {{ item }}
</li>

10、事件处理

事件修饰符

.stop//阻止其他父类单击事件
.prevent//阻止表单提交默认行为
.self
.capture
.once//只会触发一次
.passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>

<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>

<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>

<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>

<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>

<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>

按键修饰符

<!-- 仅在 `key``Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

<input @keyup.page-down="onPageDown" />

按键别名

Vue 为一些常用的按键提供了别名:

.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right

系统按键修饰符#
你可以使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发。

.ctrl
.alt
.shift
.meta

.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。

鼠标按键修饰符#
.left
.right
.middle

举例

<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />

<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>

<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
//.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>

11、表单输入绑定

v-model

//v-model
本质是两个操作
1、v-bind绑定一个value属性
2、v-on给当前元素添加一个input事件

<p>输入内容是: {{ message }}</p>
<input v-model="message" placeholder="输入内容" />

多行文本

//style="white-space: pre-line;"以保留textarea里面的格式,包括空格、回车、tab、换行
<span>多行文本展示:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="输入内容"></textarea>

点选框

export default {
  data() {
    return {
      checked: true
    }
  }
}

//html
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

多选框

export default {
  data() {
    return {
      checkedNames: []
    }
  }
}
//html
<div>选择有: {{ checkedNames }}</div>

<input type="checkbox" id="jack" value="苹果" v-model="checkedNames">
<label for="jack">苹果</label>

<input type="checkbox" id="john" value="梨子" v-model="checkedNames">
<label for="john">梨子</label>

<input type="checkbox" id="mike" value="香蕉" v-model="checkedNames">
<label for="mike">香蕉</label>

单选按钮

export default {
  data() {
    return {
      picked: 'One'
    }
  }
}
//html
<div>单选按钮: {{ picked }}</div>

<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>

<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>

单个选择器

export default {
  data() {
    return {
      selected: ''
    }
  }
}

//html
<div>下拉菜单单选择: {{ selected }}</div>

<select v-model="selected">
  <option disabled value="">请选择</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

单选择

export default {
  data() {
    return {
      selected: 'A',
      options: [
        { text: 'One', value: 'A' },
        { text: 'Two', value: 'B' },
        { text: 'Three', value: 'C' }
      ]
    }
  }
}
//html
<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>

<div>选择: {{ selected }}</div>

多选(按ctrl或下拉多个)

export default {
  data() {
    return {
      selected: []
    }
  }
}

//html
  <div>多选框: {{ selected }}</div>

  <select v-model="selected" multiple>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>

<style>
select[multiple] {
  width: 100px;
}
</style>

修饰符

v-model.lazy//在 "change" 事件后同步更新而不是 "input"
v-model.number//输入自动转换为数字
v-model.trim//默认自动去除用户输入内容中两端的空格

举例

<input v-model.lazy="message" placeholder="输入内容后确定就会变化" />

12、组件基础

定义在一个单独的 .vue文件

//命名xo.vue
<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<template>
  <button @click="count++">You clicked me {{ count }} times.</button>
</template>
//-------------------------------------
//使用组件
<script setup>
//引入xo组件
import xo from './components/Xo.vue'
</script>
//使用 <xo />
<template>
  <h1>Here is a child component!</h1>
  <xo />
</template>

传递数据 props

<!-- xo.vue -->
//props传递
<script>
export default {
  props: ['title']
}
</script>

<template>
  <h4>{{ title }}</h4>
</template>
//index
<xo title="My journey with Vue" />
<xo title="Blogging with Vue" />
<xo title="Why Vue is so fun" />

实际应用中,我们可能在父组件中会有如下的一个博客文章数组

export default {
  // ...
  data() {
    return {
      posts: [
        { id: 1, title: 'My journey with Vue' },
        { id: 2, title: 'Blogging with Vue' },
        { id: 3, title: 'Why Vue is so fun' }
      ]
    }
  }
}
//index
<xo
  v-for="post in posts"
  :key="post.id"
  :title="post.title"
 />

游荡时间:
到此一游: xoxu