文章目录
- 一、 手写JS
-
- 1-1 数组方法
- 1-2 JS相关应用题
-
- 1-2-1 判断JS实例的类型
- 1-2-2 sleep【1月10号】
- 1-2-3 js继承【1月11号】
- 1-2-4 前端跨域【1月15号】
- 1-2-5 浅拷贝【1月16号】
- 1-2-6 深拷贝【1月17号】
- 1-2-7 去重【1月18号】
- 1-2-8 列表转成树形结构/ 树转列表【1月19.20】
- 1-2-9 防抖 【2023/1/22】
- 1-2-10 节流【2023/1/23】
- 1-2-11 实现一个ajax【2023/2/2】
- 1-2-12 实现generator的自动执行器【2023/2/3】
- 1-2-13 实现hash路由【2023/2/10】
- 1-2-14 实现history路由【2023/2/11】
- 1-2-15 发布订阅【2023/2/12】
- 1-3 面向对象编程
- 1-4 Promise
- 1-5 正则
- 二、 框架
之前博客
别人博客
一、 手写JS
1-1 数组方法
1月5号 数组扁平化
- map+push
let newArr = [];
const flatten = (arr, depth=1) => {
arr.map((item) => {
// debugger;
if(depth > 0|| depth == 'Infinity') (Array.isArray(item) ? flatten(item, depth-1): newArr.push(item) ) ;
else newArr.push(item)
})
return newArr;
}
console.log(flatten(arr,Infinity))
- reduce + concat
function flatDeep(arr, d = 1) {
return d > 0
? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
: arr.slice();
}
-
const res1 = arr.flat(Infinity);
-
const res2 =JSON.stringify(arr).replace(/\[\|\]/g, '').split(',').map(item => parseInt(item))
1月6号 Array.prototype.map()
- 极其简单写法,只传入callback
const arr = [1, 2, 3]
Array.prototype.map = function (callback) {
const res = [];
for (let i = 0; i < this.length; i++) {
res.push(callback(this[i], i, this))
}
return res;
}
const res = arr.map((ele, index, arr) => {
return ele * 2
})
console.log(res)
})
Array.prototype.map = function(callback, objThis) {
// 排除回调非函数情况
if(typeof callback !== 'function') {
throw new TypeError("callback type error!");
}
// 排除this为非可迭代对象情况
if(this == null || typeof this[Symbol.iterator] !== function) {
throw new TypeError(`${
this} is not a iterable`);
}
const res = [];
for(let i = 0; i < this.length; ++i) {
res.push(callback.call(objThis, this[i], i, this))
}
return res
}
const arr = [1, 2, 3]
const res = arr.map((ele, index, arr) => {
return ele * 2
})
console.log(res)
1月7号 Array.prototype.filter()
Array.prototype._filter = function (callback) {
const res = [];
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this) && res.push(this[i])
}
return res;
};
1月8号 Array.prototype.forEach()
forEach和map类似,但是forEach不返回结果
Array.prototype._forEach = function(callback, objThis) {
if(typeof callback !== "function") {
throw new TypeError("callback type error!")
}
for(let i = 0; i < this.length; i++) {
callback.call(objThis, this[i], i, this);
}
}
1月31号 Array.prototype.reduce()
arr.reduce(function(){
},initValue)
Array.prototype.reduce = function(fn,initValue) {
let result = initValue === undefined ? this[1] : initValue;
for(let i =0; i<this.length ;i++){
result = fn(result, this[i],i,this)
}
return result;
}
1月21号 类数组转为数组
<script>
let likeNum = document.getElementsByClassName('likeSum')[0].childNodes
console.dir(likeNum);
// 方法一:
console.log(Array.from(likeNum))
// 方法二:
console.log(Array.prototype.slice.call(likeNum))
// 方法三
console.log([...likeNum])
// 没有想到的方法
// 方法四:利用concat
Array.prototype.concat.apply([], document.querySelectorAll('div'));
</script>
1-2 JS相关应用题
1-2-1 判断JS实例的类型
typeof,instanceOf,Object.prototype.toString().call()
1月9号 instanceOf
function _instanceOf(left, right) {
const rightProto = right.prototype;
const leftProto = left.__proto__;
while(leftProto.__proto__ !== null) {
if(rightProto === leftProto) {
return true;
}
}
return false
}
// 测试用例
function Person () {
}
const no = new Person()
1-2-2 sleep【1月10号】
<script>
// 普通版本
function sleep (slTime) {
let start = new Date()
while(new Date - start <= slTime) {
}
}
const t5 = new Date()
sleep(3000)
const t6 = new Date()
console.log(t6 - t5)
// promise 实现
function sleep (slTime) {
return new Promise(resolve =>{
setTimeout(resolve,slTime)
})
}
const t1 = new Date();
sleep(3000).then(()=>{
const t2 = new Date();
console.log(t2-t1);
})
// async,await实现
function sleep (slTime) {
return new Promise(resolve =>{
setTimeout(resolve,slTime)
})
}
(async function test(){
const t1 = new Date();
await sleep(3000)
const t2 = new Date();
console.log(t2 - t1);
}())
</script>
1-2-3 js继承【1月11号】
<script>
// ES5
// function father(age, name) {
// this.age = age;
// this.name = name;
// }
// father.prototype.say = function() {
// console.log('爸爸在说话');
// }
// function Child(age, name, sex) {
// father.call(this, age, name);
// this.sex = sex
// }
// Child.prototype = new father()
// let child11 = new Child(20, '哈哈', '女');
// child11.say();
// console.log(child11);
// ES6
class Father {
constructor(name, sex) {
this.name = name;
this.sex = sex;
}
sayHello() {
console.log('爸爸说话');
}
}
class Child extends Father {
constructor(name, sex, age) {
super(name, sex);
this.age = age;
}
eat() {
console.log(`${
this.name}在吃饭`);
}
}
const child = new Child('儿子');
child.eat()
</script>
1-2-4 前端跨域【1月15号】
<script>
function jsonP ({
url, params, callback}) {
return new Promise((resolve, reject) => {
let script = document.body.createElement('script')
window[callback] = function(data) {
resolve(data)
document.body.removeChild(script)
}
params = {
...params, callback}
let arr = [];
for(let key in params) {
arr.push(`${
key} = ${
params[key]}`)
}
script.src = `${
url}?${
arr.join('&')}`
document.body.appendChild(script)
})
}
jsonP({
url: '',
params: {
wd: 'I love you'},
callback: 'show'
}).then(data => {
console.log(data);
})
function jsonp({
url, params, callback}){
return new Promise((resolve, reject) => {
//动态创建script标签
let script = document.createElement('script');
//处理传入的参数
params = {
...params, callback};
//转换参数表达式
let arr = []
for(let key in params) {
arr.push(`${
key}=${
params[key]}`)
}
//在路径中,参数用 & 隔开
script.src = `${
url}?${
arr.join('&')}`
//添加 script 标签
document.body.appendChild(script);
//声明回调函数
window[callback] = function(data) {
//执行异步函数
resolve(data);
//请求完后移除该script标签
document.body.removeChild(script)
}
})
}
</script>
<!-- 在vue.config.js中添加如下配置:
devServer: {
proxy: "http://localhost:5000"
} -->
1-2-5 浅拷贝【1月16号】
- Object.assign({},obj) 第二层以上就是浅拷贝
// 方法一
let obj1 = Object.assign({
}, obj)
console.log(obj1);
obj1.c.c = 2
obj1.b = 3
console.log(obj);
// 方法二
let obj2 = {
};
for(let key in obj) {
obj2[key] = obj[key]
}
obj2.a = 3
obj2.c.c = 11
console.log(obj);
// 方法三
let obj3 = {
}
obj3 = obj
1-2-6 深拷贝【1月17号】
let obj = {
a: 1,
b: 2,
c: {
c: 1,
d: 2
}
}
// 方法一
let obj1 = JSON.parse(JSON.stringify(obj))
// 测试用例
// console.log(obj1);
// obj1.b = 22
// obj1.c.c = 11
// console.log(obj);
// 方法二
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {
}
for(let key of Object.keys(obj)) {
objClone[key] = (typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
}
return objClone
}
console.log(deepClone(obj))
1-2-7 去重【1月18号】
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
}, {
}];
// 方法一: set
let newArr = [...new Set(arr)]
console.log(newArr);
// 方法二:两层遍历+splice
function unique(arr) {
for(let i = 0; i < arr.length; i++) {
for(let j = i+1; j < arr.length; j++){
if(arr[i] === arr[j]){
arr.splice(j, 1); //会改变原来的arr
j--;
}
}
}
return arr;
}
console.log(unique(arr));
console.log(arr);
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
}, {
}];
// 方法三 : filter+indexOf
const newArr2 = [];
arr.filter((item, index) =>{
if(arr.indexOf(item) === index) {
newArr2.push(item)
}
})
console.log(newArr2);
// 方法四 : includes
let newArr3 = [];
for (let i = 0; i<arr.length; i++) {
if( !newArr3.includes(arr[i]) ) {
newArr3.push(arr[i]);
}
}
console.log(newArr3);
// 方法五:filter + hasOwnProperty----------> 貌似有点点问题
let obj = {
}
let result = arr.filter((item, index) => {
return obj.hasOwnProperty(item) ? false : (obj[item] = true)
})
console.log(result);
1-2-8 列表转成树形结构/ 树转列表【1月19.20】
<script>
let arr = [
{
id: 1, name: "部门1", pid: 0 },
{
id: 2, name: "部门2", pid: 1 },
{
id: 3, name: "部门3", pid: 1 },
{
id: 4, name: "部门4", pid: 2 },
{
id: 5, name: "部门5", pid: 2 },
{
id: 6, name: "部门6", pid: 3 },
];
function get_tree(arr) {
let list = [];
arr.forEach(element => {
const chiildren_arr = arr.filter(ele => {
return element.id === ele.pid
})
if (chiildren_arr.length > 0) {
element.children = chiildren_arr
}
if (element.pid === 0) {
list.push(element);
}
});
return list;
}
const result = get_tree(arr);
console.log(result);
//树转列表
const ToList = TreeList => {
const list = [];
const dfs = (TreeList) => {
TreeList.filter((item)=>{
if(item.children) {
dfs(item.children);
delete item.children
}
list.push(item);
})
}
dfs(TreeList)
return list
}
console.log(ToList(result))
</script>
1-2-9 防抖 【2023/1/22】
const debounce = (fn, delay) => {
const timer = null;
return function() {
clearTimeout(timer)
setTimeout(()=> {
fn.apply(this, arguments)
},delay)
}
}
1-2-10 节流【2023/1/23】
const throttle = (fn, delay) => {
const timer = null;
return function() {
if(timer) return;
timer = setTimeout(()=>{
fn.apply(this, arguments);
timer = null;
},delay)
}
}
1-2-11 实现一个ajax【2023/2/2】
<!-- 实现一个AJAX异步调用和局部刷新,通常需要以下几个步骤:
创建XMLHttpRequest对象,也就是创建一个异步调用对象.
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
设置响应HTTP请求状态变化的函数.
发送HTTP请求.
获取异步调用返回的数据.
使用JavaScript和DOM实现局部刷新. -->
<!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>AJAX原生请求</title>
</head>
<body>
<button>点击发送请求</button>
<script>
// 获取button元素
const btn = document.getElementsByTagName('button')[0];
// 绑定事件
btn.onclick = function() {
function Ajax(type, url, data, success) {
var xhr = null; // 初始化xhr
if (window.XMLHttpRequest) {
//兼容IE
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
var type = type.toUpperCase();
var random = Math.random(); //创建随机数
// GET处理缓存问题
if (type == 'GET') {
if (data) {
xhr.open('GET', url + '?' + data, true); //如果有数据就拼接
} else {
xhr.open('GET', url + '?t=' + random, true); //如果没有数据就传入一个随机数
}
xhr.send();
// POST 设置请求头
} else if (type == 'POST') {
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(data);
}
xhr.onreadystatechange = function() {
// 创建监听函数
if (xhr.readyState == 4 && xhr.status == 200) {
success(xhr.responseText);
}
}
}
// 调用函数
Ajax('get', 'https://netease-cloud-music-api-crete722p-hannah-bingo.vercel.app/playlist/hot', "", function(data) {
console.log(JSON.parse(data));
});
}
</script>
</body>
</html>
1-2-12 实现generator的自动执行器【2023/2/3】
function run(gen) {
let g = gen();
function next(data) {
let result = g.next(data);
if (result.done) return result.value;
if (result.value instanceof Promise) {
result.value.then(data => next(data));
} else {
result.value(next);
}
}
return next();
}
// ======== e.g. ==========
function func(data, cb) {
console.log(data);
cb();
}
function *gen() {
let a = yield Promise.resolve(1);
console.log(a);
let b = yield Promise.resolve(2);
console.log(b);
yield func.bind(null, a + b);
}
run(gen);
/**
output:
1
2
3
**/
1-2-13 实现hash路由【2023/2/10】
<!DOCTYPE html>
<html>
<head>
<title>hash 路由</title>
</head>
<body>
<header>
<a href="#home">首页</a>
<a href="#center">个人中心页</a>
<a href="#help">帮助页</a>
</header>
<p id="content"></p>
<script>
window.addEventListener('hashchange', (e) => {
let content = document.getElementById('content');
content.innerText = location.hash;
})
</script>
</body>
</html>
1-2-14 实现history路由【2023/2/11】
<!DOCTYPE html>
<html>
<head>
<title>history 路由</title>
</head>
<body>
<header>
<a onclick="changeRoute(this)" data-path="home">首页</a>
<a onclick="changeRoute(this)" data-path="center">个人中心页</a>
<a onclick="changeRoute(this)" data-path="help">帮助页</a>
</header>
<p id="content"></p>
<script>
function changeRoute(route) {
let path = route.dataset.path;
/**
* window.history.pushState(state, title, url)
* state:一个与添加的记录相关联的状态对象,主要用于popstate事件。该事件触发时,该对象会传入回调函数。
* 也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。
* 如果不需要这个对象,此处可以填 null。
* title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。
* url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
*/
changePage(path);
history.pushState({
content: path }, null, path);
}
/**
* 调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。
* 点击后退、前进按钮、或者在 js 中调用 history.back()、history.forward()、history.go() 方法会触发
*/
window.addEventListener('popstate', (e) => {
let content = e.state && e.state.content;
changePage(content);
});
function changePage(pageContent) {
let content = document.getElementById('content');
content.innerText = pageContent;
}
</script>
</body>
</html>
1-2-15 发布订阅【2023/2/12】
<!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>
<script>
// 解答一
class EventEmitter {
constructor() {
// key: 事件名
// value: callback [] 回调数组
this.events = {
}
}
on(name, callback) {
if (this.events[name]) {
this.events[name].push(callback)
} else {
this.events[name] = [callback]
}
}
off(name, callback) {
if (!this.message[name]) return;
if (!callback) {
// 如果没有callback,就删掉整个事件
this.message[name] = undefined;
}
this.message[name] = this.message[name].filter((item) => item !== callback);
}
emit(name, ...args) {
if (!this.events[name]) return
this.events[name].forEach(cb => cb(...args))
}
}
// 解答二
class EventEmiter {
constructor() {
this.cache = {
}; //存放不同的事件
}
on(name, fn) {
//事件名,回调
if (this.cache[name]) {
this.cache[name].push(fn)
}
else {
this.cache[name] = [fn]; //添加新事件
}
}
off(name, fn) {
//删除事件的某个回调
let tasks = this.cache[name]; //拿到对应的回调队列
if (tasks) {
const index = tasks.findIndex(f => f === fn);
if (index >= 0) {
tasks.splice(index, 1)
}
}
}
emit(name, once = false, ...args) {
if (this.cache[name]) {
//创建副本,如果回调函数内继续注册相同事件会造成死循环
let tasks = this.cache[name].slice();
for (let fn of tasks) {
fn(...args)
}
if (once) {
delete this.cache[name]
}
}
}
}
//test
let eventsBus = new EventEmiter()
let fn1 = function (name, age) {
console.log(name, age)
}
let fn2 = function (name, age) {
console.log('fn', name, age);
}
eventsBus.on("test", fn1)
eventsBus.on("test", fn2)
eventsBus.emit("test", false, "Jason", 18)
// 解答三:
// 发布订阅中心,on-订阅,off-取消订阅,emit发布,内部需要一个单独事件中心,events存储
export default class EventBus {
constructor(){
this.events= {
} }
emit(eventName, data) {
if(this.events[eventName] ){
this.events[eventName].forEach(fn => fn(data))
}
}
on(eventName, fn) {
this.events[eventName] = this.events[eventName] || []
this.events[eventName].push(fn)
}
off(eventName, fn) {
if(this.events[eventName]) {
for(let i in this.events[eventName] ) {
if(this.events[eventName][i] === fn) {
this.events[eventName].splice(i,1);
break;
}
}
}
}
}
//Jason 18
//fn Jason 18
</script>
</body>
</html>
1-3 面向对象编程
1-3-1 this关键字
1-3-1-1 call【1月14号】
Function.prototype.call = (context, ...args) => {
context = (context === undefined || context === null) ? window : context
context._fn = this
let result = context._fn(...args)
delete context._fn
return result
}
1-3-1-2 apply【1月12号】
Function.prototype.apply = function(context, args) {
context = (context === undefined || context === null) ? window : context
context._fn = this
let result = context._fn(...args)
delete context._fn
return result
}
1-3-1-3 bind【1月13号】
Function.prototype.bind2 = function(context, ...args1) {
context = (context === undefined || context === null) ? window : context
let _this = this;
return function(...args2) {
context._fn = _this;
let result = context._fn(...[...args1, ...args2])
delete context._fn
return result
}
}
1-3-1-4 实现一个new【2023/2/1】
// 手动实现一个 new 关键字的功能的函数 _new(fun, args) --> new fun(args)
function _new(fun, ...args) {
if (typeof fun !== 'function') {
return new Error('参数必须是一个函数');
}
let obj = Object.create(fun.prototype);
let res = fun.call(obj, ...args);
if (res !== null && (typeof res === 'object' || typeof res === 'function')) {
return res;
}
return obj;
}
1-4 Promise
1-4-1 Promise.all【2023/124】
Promise.all([1,2,4]);
Promise.all = function(promises){
return new Promise((resolve, reject) => {
let count = 0;
let arr = [];
for(let i = 0; i<promises.length; i++) {
promises[i].then(v=>{
count++;
arr[i] = v;
if(count === promises.length) {
// 修改状态
resolve(arr);
}
}),r=>{
reject(r);
}
}
})
}
1-4-2 Promise.reject【2023/1/25】
Promise.reject(reason)
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
1-4-3 Promise.resolve【2023/1/26】
Promise.resolve = function(value) {
return new Rromise((resolve, reject) => {
if(value instanceof Promise) {
value.then(v =>{
resolve(v);
},r=> {
reject(r);
})
}else {
resolve(value);
}
})
}
1-4-4 Promise.race【2023/1/27】
Promise.race = function(promises) {
return new Promise((resolve, reject)=>{
for(let i = 0; i<promises.length; i++) {
promises[i].then(v=>{
// 修改返回对象的状态为成功
resolve(v)
},r=>{
reject(r)
})
}
})
}
1-4-5 Promise.prototype.catch【2023/1/28】
Promise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected);
}
1-5 正则
1-5-1 正则手机号【2023/2/14】
let reg1 = /^1[44578]\d{9}$/g;
let str1 = '15555555555'
console.log(reg1.test(str1));
1-5-2 qq【2023/2/15】
let reg2 = /^[1-9][0-9]{4,9}$/g;
let str2 = '159333'
console.log(reg2.test(str2));
1-5-3 颜色【2023/2/16】
let reg3 = /#?([0-9a-fA-F]{6}) | [0-9a-fA-F]{3}/g;
let str3 = '#abc'
console.log(reg3.test(str3));
1-5-4 邮箱【2023/2/17】
let reg4 = /^([A-Za-z0-9_\-\.]+)+@([A-Za-z0-9_\-\.]+)\.([A-Za-z]{2,6})$/g;
var reg = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
let str4 = '[email protected]'
console.log(reg4.test(str4));
二、 框架
2-1 vue
2-1-1 数据代理vue2【2023/2/19】
let number = 1;
let person = {
name: '张三',
sex: '男',
age: number
}
Object.defineProperty(person, 'age', {
configurable: true,
// writable: true,
enumerable:true,
get: function() {
console.log('有人读取了age属性');
return number
},
set: function(value) {
console.log('有人修改了age属性,值是:',value);
number = value
}
})
console.log(person);
2-1-2 父子组件
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="root">
<school />
</div>
<script>
// 子组件
const student = Vue.extend({
name: 'student',
template: `
<div>子组件</div>
`,
data() {
return {
};
},
beforeCreate() {
console.log("子组件————beforeCreate...");
},
created() {
console.log("子组件————create...");
},
beforeMount() {
console.log("子组件————beforeMount...");
},
mounted() {
console.log("子组件————mounted...");
},
beforeUpdate() {
console.log("子组件————beforeUpdate...");
},
updated() {
console.log("子组件————updated...");
},
beforeDestroy() {
console.log("子组件————beforeDestroy...");
},
destroyed() {
console.log("子组件————destroyed...");
}
})
// 父组件
const school = Vue.extend({
name: 'school',
template: `
<div>
{
{text}}
<button @click="handle">点击销毁</button>
<student/>
</div>
`,
components: {
student
},
data() {
return {
text: "哈哈",
};
},
methods: {
handle() {
this.$destroy();
},
},
beforeCreate() {
console.log("父组件————beforeCreate...");
},
created() {
console.log("父组件————create...");
},
beforeMount() {
console.log("父组件————beforeMount...");
},
mounted() {
console.log("父组件————mounted...");
},
beforeUpdate() {
console.log("父组件————beforeUpdate...");
},
updated() {
console.log("父组件————updated...");
},
beforeDestroy() {
console.log("父组件————beforeDestroy...");
},
destroyed() {
console.log("父组件————destroyed...");
},
})
const vm = new Vue({
name: 'vm',
el: '#root',
components: {
school
}
})
</script>
</body>
</html>
2-1-3 组件传参
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 方法一 -->
<!-- <school name="aaa" ref="school" @get-data="getData2"/> -->
<h1>方法二</h1>
<school name="aaa" ref="school" :getData = "getData2"/>
<student2/>
</div>
<!-- <div id="root2">
<student2/>
</div> -->
<script>
const student = Vue.extend({
name: 'student',
template: `
<div>
<h5>{
{name}}</h5>
</div>
`,
data(){
return {
name: 'ntt'
}
}
})
const school = Vue.extend({
name: 'school',
template: `
<div>
<h2>{
{name2}}</h2>
<h2>接收到的props之: {
{name}}</h2>
<student/>
<hr/>
<hr/>
<hr/>
<button @click="sendData()">发送数据</button>
</div>
`,
// props: {
// name: {
// type: String,
// required: true,
// deafult: 'TY'
// },
// getData:{
// required: true
// }
// },
props: ['name','getData'],
mounted() {
this.getData(this.name2)
},
data(){
return {
name2: 'TYUT'
}
},
methods: {
sendData() {
this.$emit('get-data',this.name2)
console.log(this.name2);
}
},
components: {
student
}
})
// // 全局组件
// const student2 = Vue.extend({
// template: `
// <h2>safafad</h2>
// `
// })
// Vue.component('student2', student2)
const vm = new Vue({
name: 'vm',
el: '#root',
components: {
school
},
data() {
return {
jj:'nihao '
}
},
// mounted() {
// this.$ref.school.$on('getData',this.getData)
// },
methods: {
getData2(data) {
console.log(data);
}
},
mounted() {
}
})
</script>
</body>
</html>
2-2 react
2-2-1 JSON2DOM = react的render函数
{
tag: 'DIV',
attrs:{
id:'app'
},
children: [
{
tag: 'SPAN',
children: [
{
tag: 'A', children: [] }
]
},
{
tag: 'SPAN',
children: [
{
tag: 'A', children: [] },
{
tag: 'A', children: [] }
]
}
]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>
</div>
// 真正的渲染函数
function _render(vnode) {
// 如果是数字类型转化为字符串
if (typeof vnode === "number") {
vnode = String(vnode);
}
// 字符串类型直接就是文本节点
if (typeof vnode === "string") {
return document.createTextNode(vnode);
}
// 普通DOM
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
// 遍历属性
Object.keys(vnode.attrs).forEach((key) => {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
// 子数组进行递归操作
vnode.children.forEach((child) => dom.appendChild(_render(child)));
return dom;
}