>[success] # v-model
1. 常見表單元素:`input(radio, text, address, email....)`、`select`、 `checkbox`、 `textarea`
2. 如果想在表單元素上進行雙向綁定寫法
~~~
<input
:value="text"
@input="event => text = event.target.value">
~~~
3. `vue` 也提供了`v-model` 這個語法糖可以更簡單的進行在表單元素上創建雙向數據綁定
~~~
<input v-model="text">
~~~
4. `v-model` 配合 `input `使用時候語法糖形式綁定事件也不同[源碼參考](https://github1s.com/vuejs/core/blob/HEAD/packages/runtime-dom/src/directives/vModel.ts#L52-L59)
* `text `和 `textarea `元素使用 `value property` 和 `input `事件;
* `checkbox `和 `radio `使用 `checked property` 和 `change `事件;
* `select `字段將 `value `作為 `prop `并將 `change `作為事件。
5. 組件也可以使用`v-model` 具體參考組件章節
>[info] ## 原生實現類vue 雙向綁定
1. `v-model`配合`input`使用時候語法糖形式綁定事件也不同[源碼參考](https://github1s.com/vuejs/core/blob/HEAD/packages/runtime-dom/src/directives/vModel.ts#L52-L59)因此本質上還是對dom 操作,使用原生做一個類似實現效果
>[danger] ##### input[text] -- onInput

~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<div id="inputTextVal"></div>
<input id="text" value="" />
</div>
<script>
// 普通文本輸入
;(function inputText() {
const textDom = document.getElementById('text')
textDom.addEventListener('input', function (e) {
document.getElementById('checkboxVal').innerText =
e.target.value
console.log(e.target.value)
})
})()
</script>
</body>
</html>
~~~
>[danger] ##### input[checkbox] -- onChange
1. `checkbox` 在原生中如果被選中會在節點上增加`checked` 屬性,只要收集`name`屬性標記相同一組`checkbox` 中`value`屬性即可

~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<div id="checkboxVal"></div>
<input type="checkbox" value="1" /> 足球
<input type="checkbox" value="2" /> 籃球
<input type="checkbox" value="3" /> 乒乓球
</div>
<script>
// checkbox 多選
;(function inputCheckbox() {
const ls = []
const checkList = document.querySelectorAll(
'input[type="checkbox"]'
)
// 綁定事件
function checkChange(callback) {
checkList.forEach((item) => {
item.addEventListener('change', function (e) {
if (e.target.checked) {
ls.push(e.target.value)
} else {
const index = ls.findIndex((val) => {
val === e.target.value
})
ls.splice(index, 1)
}
callback?.()
})
})
}
// 數據渲染頁面
checkChange(() => {
document.getElementById('checkboxVal').innerText =
ls.toString()
})
})()
</script>
</body>
</html>
~~~
>[danger] ##### radio -- onChange
1. `radio` 需要配合 `name` 字段形成互斥,綁定`change` 事件獲取 `value` 即可

~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<div id="radioVal"></div>
<input type="radio" name="gender" value="1" /> 男
<input type="radio" name="gender" value="2" /> 女
</div>
<script>
;(function inputRadio() {
const radioChecked= document.querySelector(
'input[type="radio"]'
)
// 綁定事件
function checkChange(callback) {
radioChecked.addEventListener('change', function (e) {
callback?.(e.target.value)
})
}
// 數據渲染頁面
checkChange((val) => {
document.getElementById('radioVal').innerText = val
})
})()
</script>
</body>
</html>
~~~
>[danger] ##### select -- onChange

~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<div id="selectedVal"></div>
<select id="ss">
<option value="1">大連</option>
<option value="2">上海</option>
<option value="3">北京</option>
<option value="4" id="op1">天津</option>
</select>
</div>
<script>
;(function selected() {
const selected = document.querySelector('#ss')
// 綁定事件
selected.addEventListener('change', function (e) {
console.log(e.target.value)
const option = document.querySelector(
`option[value="${e.target.value}"]`
)
document.getElementById('selectedVal').innerText =
e.target.value + ',' + option.textContent
})
})()
</script>
</body>
</html>
~~~
>[info] ## v-model 和 原生屬性
1. `v-model`會忽略任何表單元素上初始的`value`、`checked`或`selected`attribute。它將始終將當前綁定的 JavaScript 狀態視為數據的正確來源。你應該在 JavaScript 中使用`data`選項來聲明該初始值。理解為在上面原生案例可以知道其實通過`dom `原生提供的固定標記屬性來獲取選中值,當你在`vue `中使用` v-model`,這些屬性將會被忽略,v-model 只會對自己數據源負責
vue自己`true-value`和`false-value` 也需要后續補充
>[danger] ##### 修飾符 - lazy
1. 默認情況下,`v-model`在進行雙向綁定時,綁定的是`input`事件,那么會在每次內容輸入后就將最新的值和綁定的屬性進行同步
2. `v-model`后跟上lazy修飾符,那么會將綁定的事件切換為 `change `事件,只有在提交時才會觸發
~~~
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
~~~
>[danger] ##### 修飾符 - number
1. `v-model`綁定后的值總是`string`類型,`vue2`即使在我們設置`type`為`number`也是`string`類型,`vue3`在`number`修飾符會在輸入框有`type="number"`時自動啟用
2. 希望轉換為數字類型,那么可以使用 `.number `修飾符
~~~
<input v-model.number="age" />
~~~
>[danger] ##### 修飾符 - .trim
1. 你想要默認自動去除用戶輸入內容中兩端的空格,你可以在` v-model `后添加` .trim` 修飾
~~~
<input v-model.trim="msg" />
~~~
>[danger] ##### 官網給的提示
對于需要使用[IME](https://en.wikipedia.org/wiki/Input_method)的語言 (中文,日文和韓文等),你會發現`v-model`不會在 IME 輸入還在拼字階段時觸發更新。如果你的確想在拼字階段也觸發更新,請直接使用自己的`input`事件監聽器和`value`綁定而不要使用`v-model`。
>[danger] ##### 官網參考
[v-model](https://cn.vuejs.org/guide/essentials/forms.html#checkbox-2)
- 官網給的工具
- 聲明vue2 和 vue3
- 指令速覽
- Mustache -- 語法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 顯示原始的Mustache標簽
- v-cloak -- 遮蓋
- v-memo(新)-- 緩存指定值
- v-if/v-show -- 條件渲染
- v-for -- 循環
- v-bind -- 知識
- v-bind -- 修飾符
- v-on -- 點擊事件
- v-model -- 雙向綁定
- 其他基礎知識速覽
- 快速使用
- 常識知識點
- key -- 作用 (后續要更新)
- computed -- 計算屬性
- watch -- 偵聽
- 防抖和節流
- vue3 -- 生命周期
- vue-cli 和 vite 項目搭建方法
- vite -- 導入動態圖片
- 組件
- 單文件組件 -- SFC
- 組件通信 -- porp
- 組件通信 -- $emit
- 組件通信 -- Provide / Inject
- 組件通信 -- 全局事件總線mitt庫
- 插槽 -- slot
- 整體使用案例
- 動態組件 -- is
- keep-alive
- 分包 -- 異步組價
- mixin -- 混入
- v-model-- 組件
- 使用計算屬性
- v-model -- 自定義修飾符
- Suspense -- 實驗屬性
- Teleport -- 指定掛載
- 組件實例 -- $ 屬性
- Option API VS Composition API
- Setup -- 組合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 場景
- api -- toRefs 和 toRef
- api -- readonly
- 判斷性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 簡單使用composition Api
- 響應性語法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 語法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定義指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同點
- $children -- 移除
- v-for 和 ref
- attribute 強制行為
- 按鍵修飾符
- v-if 和 v-for 優先級
- 組件使用 v-model -- 非兼容
- 組件
- h -- 函數
- jsx -- 編寫
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 簡單實現
- 安裝即使用
- 路由懶加載
- router-view
- router-link
- 路由匹配規則
- 404 頁面配置
- 路由嵌套
- 路由組件傳參
- 路由重定向和別名
- 路由跳轉方法
- 命名路由
- 命名視圖
- Composition API
- 路由守衛
- 路由元信息
- 路由其他方法 -- 添加/刪除/獲取
- 服務器配置映射
- 其他
- Vuex -- 狀態管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 數據同步
- 小技巧
- Pinia -- 狀態管理
- 開始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源碼解讀
- 開發感悟
- 練手項目