VUE2関連
私のブログはズームインしたワイドスクリーンで表示する必要があるかもしれませんが、画像のバランスが取れません。申し訳ありません。
1. 命令、補間
2. 計算して監視する
計算された計算された属性、v-model には get と set が必要です
<template>
<div>
<p>num :{
{
num }} 答案: 20</p>
<p>double1 {
{
double1 }} 答案: 40</p>
<input v-model="double2" />
</div>
</template>
<script>
export default {
data() {
return {
num: 20,
}
},
computed: {
double1() {
return this.num * 2
},
double2: {
// v-model使用一定要有 get和set
get() {
// 如果只有一个 get 或 set 会报错
return this.num * 2
},
set(val) {
this.num = val / 2
},
},
},
}
</script>
ウォッチモニター、リファレンスタイプ、oldValを取得できません。
<template>
<div>
<input v-model="name" />
<input v-model="info.city" />
</div>
</template>
<script>
export default {
data() {
return {
name: 'watch监听',
info: {
city: '北京',
},
}
},
watch: {
// watch监听
name(oldVal, val) {
// 值类型,可正常拿到 oldVal 和 val
console.log('watch name', oldVal, val)
},
info: {
handler(oldVal, val) {
// 引用类型, 拿不到 oldVal 。 因为指针相同,此时已经指向了新的 val
console.log('watch info', oldVal, val)
},
deep: true, // 深度监听
},
},
}
</script>
3. クラスとスタイル
4. 条件付きレンダリング
5. ループリスト v-for
6. イベントイベント
- 1. イベント イベントはネイティブです。2. イベントは現在の要素に付加されます。
7. イベント修飾子
8. フォーム
<template>
<div>
<p>输入框 : {
{
name }}</p>
<!-- 1. trime 截取前后空格
2. lazy 类似防抖效果
3. number 转换为数字 -->
<input type="text" v-model.trim="name" />
<input type="text" v-model.lazy="name" />
<input type="text" v-model.number="age" />
<p>多行文本 : {
{
desc }}</p>
<textarea v-model="desc"></textarea>
<!-- 注意,<textarea> {
{
desc }} </textarea> 是不允许的!!!-->
<p>复选框 {
{
checked }}</p>
<input type="checkbox" v-model="checkbox" />
<p>多个复选框 {
{
checkedNames }}</p>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="join" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<p>单选{
{
gender }}</p>
<input type="radio" id="male" value="male" v-model="gender" />
<label for="male">男</label>
<input type="radio" id="female" value="female" v-model="gender" />
<label for="female">女</label>
<p>下拉列表选择 {
{
selected }}</p>
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>下拉列表选择 (多选) {
{
selectedList }}</p>
<select v-model="selectedList" multiple>
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</div>
</template>
<script>
export default {
data() {
return {
name: '德玛西亚',
age: 18,
desc: '自我介绍',
checked: true, // 单个复选框
checkedNames: [], // 多个复选框
gender: 'male', // 性别
selected: '', // 下拉列表单选
selectedList: [], // 下拉列表多选
}
},
}
</script>
9. VUE コンポーネントの使用
10. カスタム v モデル
11. $nextTick
<template>
<div id="app">
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{
{
item }}
</li>
</ul>
<button @click="addItem">添加一项</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
list: ['a', 'b', 'c'],
}
},
methods: {
addItem() {
this.list.push(`${
Date.now()}`)
this.list.push(`${
Date.now()}`)
this.list.push(`${
Date.now()}`)
// 获取 DOM 元素
const ulElem = this.$refs.ul1
console.log(ulElem.childNodes.length)
},
},
}
</script>
12. スロットの複数使用
- 1. デフォルトのスロット
- 2. 名前付きスロット
同じコンポーネント内で複数のスロットを使用する必要がある場合は、名前付きスロットを使用する必要があります。
- 3. スコープ付きスロット
- スコープ付きスロット
13. 動的コンポーネント
<template>
<div>
<!-- 动态组件 -->
<component :is="NextTickName"></component>
<!-- 动态组件 -->
<div v-for="(val, key) in newsData" :key="key">
<component :is="val.type"></component>
</div>
</div>
</template>
<script>
import NextTick from './NextTick'
export default {
components: {
// 注册组件
NextTick,
},
data() {
return {
// 动态组件
NextTickName: 'NextTick',
// 动态组件
newsData: {
1: {
type: 'text',
},
2: {
type: 'text',
},
3: {
type: 'image',
},
},
}
},
}
</script>
14. 非同期コンポーネント
15.キープアライブキャッシュコンポーネント
<template>
<div>
<button @click="changeState('A')">A</button>
<button @click="changeState('B')">B</button>
<button @click="changeState('C')">C</button>
<KeepAliveStageA v-if="state === 'A'" />
<KeepAliveStageB v-if="state === 'B'" />
<KeepAliveStageC v-if="state === 'C'" />
</div>
</template>
<script>
import KeepAliveStageA from './KeepAliveStateA' // 引入组件
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'
export default {
components: {
KeepAliveStageA,
KeepAliveStageB,
KeepAliveStageC, // 注册组件
},
data() {
return {
state: 'A', // 默认显示 A 组件
}
},
methods: {
// 点击事件,动态传值,修改 data中的state,从而改变组件
changeState(state) {
this.state = state
},
},
}
</script>
16. ミックスインの使用
17. VUEX
18. ビュールーター
上級者、準備をしてみましょう
1. Vueの原則
2. MVVMの理解方法
3. Vue レスポンシブ
// 触发更新视图
function updateView() {
console.log('视图更新');
}
// 监听数组,需要重新定义数组的原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型指向 oldArrayProperty, 再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty)
// methodName 其实就是 push,pop等 这些名字
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
// 对每个方法都进行一个 定义
arrProto[methodName] = function () {
updateView() // 触发视图更新
oldArrayProperty[methodName].call(this, ...arguments)
// oldArrayProperty 方法就是 Array.prototype.call(this,...arguments)
}
})
// 重新定义属性,监听起来
// (target 就是data , key 就是data中的name或age , value 就是name的值zhangsan 或 age 的值20)
function defineReactive(target, key, value) {
// 深度监听,针对 info 层级比较深的 结构
observer(value)
// 核心 API
Object.defineProperty(target, key, {
get() {
// 获取
return value
},
set(newValue) {
// 设置
// 例如 data.name = '测试名字' 就会走这里
if (newValue !== value) {
// 针对 info 也需要深度监听
observer(newValue)
// 设置新值
// 注意,value 一直在闭包中,此处设置完之后,再get时也是会获取最新的数据
value = newValue
//触发更新视图
updateView()
}
}
})
}
// 监听对象属性
function observer(target) {
if (typeof target !== 'object' || target === null) {
//监听不是对象或数组,返回
return target
}
// 污染全局 Array 原型 (一定不可以!!!)
// 必须重新定义原型 不可污染全局 Array 原型
// Array.prototype.push = function () {
// updateView()
// ...
// }
// 如果是数组
if (Array.isArray(target)) {
target._proto_ = arrProto
}
// 重新定义各个属性 (for in 也可以遍历数组)
for (let key in target) {
defineReactive(target, key, target[key])
}
}
// 准备数据
const data = {
name: 'zhangsan',
age: 20,
// 针对 info 来说target 就是data , key 就是info , age 就是对象{}
info: {
address: '北京' // 需要深度监听
},
nums: [10, 20, 30]
}
// 监听数据
observer(data)
// 测试
data.name = '测试名字'
data.age = 25
// console.log('age', data.age); // 打印结果'age', 25
// data.x = '100' // 新增属性,监听不到 -- 所以有 Vue..set
// delete data.name // 删除属性,监听不到 -- 所以有 Vue.delete
data.info.address = '上海' // 深度监听
data.nums.push(4) // 监听数组
- コード内の情報を例にとると、この
info: { { {}}}
ように、常にオブザーバー(値)に移動し、最後まで再帰されます。
4. 仮想 DOM (Virtual DOM) と diff アルゴリズム
github で詳しく説明されている snabbdom の記事を参照してください。
5. テンプレートのコンパイル
// 依赖 vue-template-compiler 转换模版
const compiler = require('vue-template-compiler')
// 插值
const template = `<p>{
{message}</p>`
with (this) {
return _c('p', [_v(_s(message))]) }
// with (this) { return createElement('p', [createTextNode(toString(message))]) }
// h 函数 执行返回的 是 vnode
// createElement 执行返回的也是 vnode
// 表达式
const template1 = `<p>{
{ flag? message: 'no message found' }}</p>`
with (this) {
return _c('p', [_v(_s(flag ? message : 'no message found'))]) }
with (this) {
return createElement('p', [createTextNode(toString(flag ? message : 'no message found'))]) }
// 属性 和 动态属性
const template2 = `
<div id='div' class="container">
<img :src = "imgUrl"/>
</div> `
// staticClass 原先是 className ,再 vue 编译完后变成了staticClass
with (this) {
return _c('div'), {
staticClass: "container", attrs: {
"id": "div1" } }, [_c('img')] }
with (this) {
return createElement('div'), {
staticClass: "container", Attributes: {
"id": "div1" } }, [createElement('img')] }
// 条件编译
const template3 = `
<div>
<p v-if="flag ==='a'">A</p>
<p v-else>B</p>
</div>
`
with (this) {
return _c('div', ['div', [(flag === 'a') ? _c('p', [_v("A")]) : _c('p', [_v("B")])]]) }
with (this) {
return createElement('div', ['div', [(flag === 'a') ? createElement('p', [createTextNode("A")]) : createElement('p', [createTextNode("B")])]]) }
// 循环
const template4 = `
<ul>
<li v-for="item in list" :key="item.id">{
{item.title}}</li>
</ul> `
with (this) {
return _c('ul', _l((list), function (item) {
return _c('li', {
key: item.id }, (_v(_s(item.title)))) })) }
with (this) {
return createElement('ul', renderList((list), function (item) {
return createElement('li', {
key: item.id }, (createTextNode(toString(item.title)))) })) }
// 事件
const template5 = `<button @click = "clickHandler">submit</button>` // on代表所有的事件
with (this) {
return _c('button', {
on: {
"click": clickHandler } }, [_v("submit")]) }
with (this) {
return createElement('button', {
on: {
"click": clickHandler } }, [createTextNode("submit")]) }
// v-model
const template6 = `<input type="text" v-model="name">`
with (this) {
return _c('input', {
directives: [{
name: "model", rawName: "v-model", value: (name), expression: "name" }],
attrs: {
"type": "text" }, domProps: {
"value": (name) },
on: {
"input": function ($event) {
if ($event.target.composing) return; name = $event.target.value } }
})
}
// 上面都是 render 函数
// 执行 render 函数 返回 vnode
// 编译
const res = compiler.compile(template)
6. コンポーネントのレンダリング/更新プロセス
7. 非同期レンダリング。上記の $nextick を参照してください。
8. ルーティングの原理 vue-router
ハッシュルート(#)
<body>
<p>hash test</p>
<button id="btn1">修改 hash</button>
<script>
// hash变化 :包括
// a: JS 修改 url
// b: 手动修改 url 的 hash , 不会触发刷新,不会触发前进后退
// C: 浏览器前进、后退 , 不会触发刷新
window.onhashchange = (event) => {
console.log('old url', event.oldUrl);
console.log('new url', event.newUrl);
console.log('hash:', location.hash);
}
// 页面初次加载, 获取 hash
document.addEventListener('DOMContentLoaded', () => {
console.log('hash:', location.hash);
})
// JS 修改 url
document.getElementById('btn1').addEventListener('click', () => {
location.href = '#/user'
})
</script>
</body>
- window.onhashchange は JavaScript のイベント ハンドラーです。
- これは、URL 内のハッシュ値 (つまり、# 記号の後の内容) が変更されたかどうかを検出するために使用されます。
- このイベントは、ブラウザーの履歴を前方または後方に移動するときにも発生します。
- このイベントは、URL ハッシュが変更されたときにページ全体をリロードせずにページ コンテンツを更新するシングル ページ アプリケーション (SPA) を構築するためによく使用されます。
履歴ルーティング
<body>
<p>history API test</p>
<button id="btn1">修改 hash</button>
<script>
// 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname); // index.html
})
// 【注意】 用 pushState 方式, 浏览不会刷新页面
document.getElementById('btn1').addEventListener('click', () => {
const state = {
name: 'page1' }
console.log('切换路由到', 'page1');
history.pushState(state, '', 'page1') //重要!!
})
// 监听 浏览器前进、后退
window.onpopstate = (event) => {
// 重要!!
console.log('onpopstate', event.state, location.pathname);
}
</script>
</body>
Vue の実際のテストのウォークスルー
- 赤いボックス内のデータを確認すると、関数はオブジェクトを返し、
看似
デフォルトの是一个对象,实际上
.vue ファイルをエクスポートします。在被编译出来以后,这个vue实际上是一个class是一个类,vue组件是一个class,在每个地方使用这个组件时,相当于对class进行了一个实例化,在实例化时执行这个data,如果这个data不是一个函数的话,那每一个组件的实例都一样了就共享了,那就麻烦了。
-
如果在这个组件实例化一个,在其他组件实例化一个,
data が関数ではない場合、那在这个组件改了
data 内の名前,那其他组件的name也会随之改变。
- したがって、データが関数の場合、左側と右側に 1 つずつインスタンスを作成すると、この関数が実行され、両方のデータがクロージャ内にあるため、2 つの極 (コンポーネント) は互いに影響しません。データ内容の変更のいずれかが他のコンポーネントのデータに影響することはありません。したがって、データは関数でなければなりません。