Vue学习笔记(5)

1、回顾复习

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
  </div>

  <script src="./vue.js"></script>
  <script>
    // 资料站:
    // 1 XSS攻击: http://qingbob.com/Excess-XSS/
    // 2 官网(Vue)
    // 3 知乎
    // 4 掘金
    // 5 思否 https://segmentfault.com/channel/frontend
    // 6 简书
    // 7 CSDN
    // 8 总结:科学上网,善用搜索工具(google) 蓝灯


    // 0 安装插件:Settings Sync
    // 1 按F1,出现命令窗口
    // 2 输入 sync ,选择 下载设置
    // 3 到 https://github.com/settings/tokens 中创建自己的 token
    //  创建的时候,勾选 gist
    // 4 将github生成的 token 值粘贴到文本框中
    // 5 再输入 694238a721b9444078617c5ac2100776 (老师vscode的gist id)
    // 6 下载完成后,重新打开vscode就可以了

  </script>
</body>

</html>

2、虚拟DOM的说明

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app"></div>
  <script>
    const dv = document.getElementById('app')
    console.dir(dv)

    let count = 0, str = ''
    for (let k in dv) {
      count++
      str += k + ' '
    }

    console.log(str, count)
  </script>
</body>

</html>

Virtual DOM and Diff

Virtual DOM

  • 虚拟 DOM,实际上就是一个 js 对象

Vue 模板渲染(render)和更新(patch)

  • 1 第一次渲染创建一棵虚拟DOM树(js 对象)

  • 2 数据发生改变后,生成一棵新的虚拟 DOM 树(js 对象)

  • 3 对比新旧两棵虚拟 DOM 树(js 对象),通过diff算法找到并记录差异的地方

  • 4 只将差异的地方重新渲染到页面中

图例

 

3、Vue中的组件

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <!-- 局部组件 -->
    <!-- <local></local> -->
    <child></child>

    <!-- 全局组件 -->
    <hello></hello>
  </div>

  <script src="./vue.js"></script>
  <script>
    // 两种组件:
    // 1 全局组件
    // 2 局部组件:只能在当前 父组件 的模板中使用,而不能在其他地方使用!!!

    // 创建全局组件
    Vue.component('hello', {
      template: `
        <div>
          <child></child>
          <h1 @click="fn">这是 Hello 组件 => {{ msg }}</h1>
        </div>
      `,

      // 数据
      data() {
        return {
          msg: 'Hello component'
        }
      },

      created() {
        console.log('钩子函数执行了')
      },

      methods: {
        fn() {
          this.msg = '修改'
        }
      },

      components: {
        child: {
          template: `
            <p>Hello 组件的局部组件</p>
          `
        }
      }
    })

    const localConfig = {
      template: `
        <p>这是 Vue 实例中的局部组件</p>
      `
    }

    const vm = new Vue({
      el: '#app',
      data: {

      },

      // 通过 components 配置项来创建局部组件
      components: {
        local: localConfig
      }
    })
  </script>
</body>

</html>

4、组件的说明

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <hello></hello>
  </div>

  <script src="./vue.js"></script>
  <script>
    // 组件是一个独立、封闭的个体
    // 所以,组件是无法直接使用外部数据的!!!
    // 如果想让组件能够使用外部的数据,那就用到 组件通讯 的知识了

    // 组件通讯的三种情况:
    // 1 父组件将数据传递个子组件:父 -> 子
    // 2 子组件将数据传递给父组件:子 -> 父
    // 3 兄弟组件(非父子组件)

    // Vue.component('hello', {
    //   template: `
    //     <div>这是 Hello 组件 -- {{ msg }}</div>
    //   `
    // })

    const vm = new Vue({
      el: '#app',
      data: {
        msg: '这是 Vue 实例提供的数据'
      },

      components: {
        hello: {
          template: `
            <div>这是 Hello 子组件 -- {{ msg }}</div>
          `
        }
      }
    })
  </script>
</body>

</html>

5、组件通讯 -- 父到子

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <!-- 父组件的模板 -->
  <div id="app">
    <!-- 子组件的模板 -->
    <hello ppp="18" gender="male" :parent-msg="msg"></hello>
  </div>

  <script src="./vue.js"></script>
  <script>
    // 1 父到子
    // 父组件:vm实例
    // 子组件:hello组件

    // 1 在子组件标签上添加一个属性(ppp)
    // 2 在子组件中通过 props 属性,来接受这个数据
    // 3 就可以使用接受到的 ppp 数据了

    const vm = new Vue({
      el: '#app',
      data: {
        msg: '这是 Vue 实例提供的数据'
      },

      components: {
        hello: {
          template: `
            <div>这是 Hello 子组件 -- {{ ppp }} | {{ gender }} | {{ parentMsg }}</div>
          `,

          // 通过 props 属性,来指定该组件接受的数据
          // props 的使用方式与 data 相同
          props: ['ppp', 'gender', 'parentMsg']
        }
      }
    })
  </script>
</body>

</html>

6、组件通讯 --- 子到父

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h1>{{ age }}</h1>

    <!-- 2 给子组件传递一个自定义事件 getmsg ,它的值是 getChildMsg 方法 -->
    <child @getmsg="getChildMsg"></child>
  </div>

  <script src="./vue.js"></script>
  <script>
    // 子到父:
    // 子组件:child组件
    // 父组件:vm实例

    // 步骤:
    // 1 父组件提供一个方法
    //  这个方法是子组件调用的,数据通过方法的参数拿到
    // 2 将这个方法传递给子组件
    // 3 由子组件触发这个方法,将要传递的数据作为方法的参数传递

    const vm = new Vue({
      el: '#app',
      data: {
        age: 0
      },
      // 1 准备一个方法
      methods: {
        getChildMsg(data) {
          console.log('接受到子组件传递过来的数据为:', data)

          this.age = data
        }
      },
      components: {
        child: {
          template: `
            <div>
              <button @click="fn">传递数据给父组件</button>
            </div>
          `,
          methods: {
            fn() {
              // 3 触发父组件中传递过来的方法
              this.$emit('getmsg', 19)
            }
          }
        }
      }
    })
  </script>
</body>

</html>

SPA  以及 单页面应用程序

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">
		div {
			height: 500px;
			width: 100%;
			background-color: hotpink;
		}
	</style>
</head>

<body>
	<ul>
		<li>
			<a href="#/find">发现音乐</a>
		</li>
		<li>
			<a href="#/my">我的音乐</a>
		</li>
		<li>
			<a href="#/friend">朋友</a>
		</li>
	</ul>

	<div id="content">
		<!-- 这是内容区域 -->
	</div>

	<script src="./node_modules/axios/dist/axios.js"></script>
	<script type="text/javascript">
		// a标签锚点值的作用:页面内部跳转

		// 如何实现单页面应用程序???
		// 
		// 1 ajax
		// 2 hash 哈希值(a标签的锚点值)
		// 3 hashchange 事件:监视 hash 值的变化

		hashChangeHanlder()

		window.addEventListener('hashchange', hashChangeHanlder)

		function hashChangeHanlder() {
			// console.log('URL中的哈希值改变了', location.hash)

			// 获取哈希值
			const hash = location.hash

			switch (hash) {
				case '#/my':
					axios
						.get('./my.json')
						.then(res => {
							// console.log(res.data)
							document.getElementById('content').innerText = res.data.content
						})
					break;

				case '#/friend':
					axios
						.get('./friend.json')
						.then(res => {
							// console.log(res.data)
							document.getElementById('content').innerText = res.data.content
						})

					break;
				
				default:
					axios
						.get('./find.json')
						.then(res => {
							// console.log(res.data)
							document.getElementById('content').innerText = res.data.content
						})
					break;
			}
		}
	</script>
</body>

</html>

7、总结

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <child :msg="msg" @get-child-msg="getChildMsg"></child>
  </div>
  <script src="./vue.js"></script>
  <script>
    // 父到子: props
    // 子到父:
    //  1 父组件提供一个方法
    //  2 将这个方法传递给子组件
    //  3 由子组件触发这个方法,将数据作为参数传递

    const vm = new Vue({
      el: '#app',
      data: {
        msg: '父组件'
      },

      // 1 准备一个方法
      methods: {
        getChildMsg(data) {
          console.log('接受到子组件传递过来的数据为:', data)
        }
      },

      components: {
        child: {
          template: `
            <div>
              <div>子组件,接受到父组件中传递过来的数据为:{{ msg }}</div>
              <button @click="fn">给父组件传递数据</button>   
            </div>
          `,

          props: ['msg'],

          // 进入页面,就将数据传递给父组件
          created() {
            this.$emit('get-child-msg', { color: 'red' })
          },

          methods: {
            fn() {
              this.$emit('get-child-msg', ['red', 'pink'])
            }
          }
        }
      }
    })
  </script>
</body>

</html>

8、todomvc -app组件通讯 - 1 抽离结构

9、todomvc - app 组件通讯 

10、props是 只读的

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <!-- 父组件的模板 -->
  <div id="app">
    <!-- 子组件的模板 -->
    <hello :parentmsg="msg"></hello>
  </div>

  <script src="./vue.js"></script>
  <script>
    // props 是只读的,不能直接修改 props 中的数据
    // 如果要修改数据的话,而应该使用 data 或者 computed 计算属性来代替

    const vm = new Vue({
      el: '#app',
      data: {
        msg: '这是 Vue 实例提供的数据'
      },

      components: {
        hello: {
          template: `
            <div>
              <div>这是 Hello 子组件 -- {{ mymsg }}</div>  
              <button @click="fn">修改props</button>
            </div>
          `,
          props: ['parentmsg'],

          data() {
            return {
              mymsg: this.parentmsg
            }
          },

          methods: {
            fn() {
              console.log(this.mymsg)

              this.mymsg = '修改'
            }
          }
        }
      }
    })
  </script>
</body>

</html>

11、JS中的引用类型

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script>
    // 父组件的数据:
    const obj = [
      { id: 1, name: '吃饭', completed: false }
    ]

    // 传递给子组件,obj1 就是子组件中的数据
    const obj1 = obj

    // 只是改变了对象中的某个属性,而没有改变 obj 的指向
    obj1.completed = true

    // 改变obj的指向:
    // obj = []
  </script>
</body>

</html>

12、Vue中的单向数据流

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <button @click="changeMsg">修改父组件中的数据</button>
    <child :msg="msg"></child>
  </div>
  <script src="./vue.js"></script>
  <script>
    // 两个组件之间的数据流动:
    // 
    // 单项数据流: 父组件中的数据可以通过props流动到子组件中,并且当父组件中的数据
    //             发生改变的时候,子组件会自动接收到这个修改后的数据,
    //             并且更新页面中的内容。这就是 Vue 中的单项数据流

    // 所以,数据一般是由父组件提供的,当父组件中的数据发生了改变,子组件就会自动接收到
    // 这个数据的变化,从而更新子组件

    // 双向数据绑定: data中的数据(Model) 与 视图中的表单元素(View)

    const vm = new Vue({
      el: '#app',
      data: {
        msg: 'parent'
      },

      methods: {
        changeMsg() {
          this.msg = 'change'
        }
      },

      components: {
        child: {
          template: `
            <p>接收到父组件中的数据为:{{ msg }}</p>
          `,

          props: ['msg']
        }
      }
    })
  </script>
</body>

</html>

13、组件通讯 - 兄弟组件

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <jack></jack>
    <rose></rose>
  </div>

  <script src="./vue.js"></script>
  <script>
    // 兄弟组件之间的通讯:
    // 两个组件: jack和rose
    // jack 要对 rose 说明: i love u

    // 步骤:
    // 1 创建一个空Vue实例,也就是一个 bus ( 事件总线 )
    // 2 一个组件注册事件( bus.$on(事件名称, () => {}) )
    // 3 另一个组件触发事件( bus.$emit(事件名称, 数据) )
    // 注意:一定要是同一个 bus!!!

    // 创建一个bus
    const bus = new Vue()

    Vue.component('jack', {
      template: `
        <div>
          我是jack,我要对 rose 说:
          <button @click="fn">告诉rose:i love u</button>
        </div>
      `,

      methods: {
        fn() {
          // 触发事件
          // 第一个参数表示:事件名称,需要与 注册事件 名称一致
          // 第二个参数表示:要传递的数据
          bus.$emit('love', 'i love u')
        }
      }
    })

    Vue.component('rose', {
      template: `
        <div>
          我是rose,jack 对我说:{{ msg }}
        </div>
      `,

      data() {
        return {
          msg: ''
        }
      },

      created() {
        // 注册事件
        // 第一个参数表示:事件名称
        // 第二个参数表示:事件处理程序
        bus.$on('love', (data) => {
          console.log('rose 接收到 jack 传递过来的数据:', data)

          this.msg = data
        })
      }
    })

    const vm = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    /* 容器 */

    .container {
      width: 150px;
    }

    /* 灯 */

    .light {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      text-align: center;
      line-height: 100px;
      margin: 0 auto;
      color: #fff;
      background-color: #000;
    }

    /* 开灯 */

    .turn-on {
      background-color: #ff0;
      color: #000;
    }

    /* 灯座 */

    .bottom {
      width: 150px;
      height: 50px;
      margin-top: 10px;
      line-height: 50px;
      text-align: center;
      color: #fff;
      background-color: #000;
    }
  </style>
</head>

<body>
  <div id="app" class="container">
    <light-head></light-head>
    <light-bottom></light-bottom>
  </div>
  <script src="./vue.js"></script>
  <script>
    const bus = new Vue()

    Vue.component('light-head', {
      template: `
        <div class="light" :class="{ 'turn-on': isOn }">
          {{ msg }}
        </div>
      `,

      data() {
        return {
          msg: '我是一盏灯',
          isOn: false
        }
      },

      created() {
        bus.$on('来电了', (state) => {
          this.isOn = state
        })
      }
    })

    Vue.component('light-bottom', {
      template: `
        <div class="bottom">
          <button @click="on">开</button>
          <button @click="off">关</button>
        </div>
      `,

      methods: {
        on() {
          bus.$emit('来电了', true)
        },
        off() {
          bus.$emit('来电了', false)
        }
      }
    })

    var vm = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>

</html>

14、总结

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script>
    // todomvc 案例,有点复杂
    // 但是,至少要完成:
    // 1 抽离三个组件
    // 2 渲染列表数据( 父 -> 子 )
    // 3 添加任务 ( 子 -> 父 )
  </script>
</body>

</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值