WY-DOM编程

DOM


Document Object Model

  • DOM Core
  • DOM HTML
  • DOM Style
  • DOM Event

节点相关


获取节点

获取节点 方法比较

修改节点

  • textContent
  • innerText ( 有兼容问题 )

element.textContent 节点及其后代节点的文本内容

代码
 users.textContent;
结果
user_last.textContent; //Kash
user_last.textContent = " Tom "; //设置 

ie9以下不支持

element.innerText 节点及其后代节点的文本内容

与 textContent 用法一样。但,innerText 不规范,ff不支持

兼容方案

 if( !('innerText' in document.body) ){
    HTMLElement.prototype.__defineGetter__("innerText",function(){
        return this.textContent;
    })

    HTMLElement.prototype.__defineSetter__("innerText",function(s){
        return this.textContent = s;
    })
}

插入节点

  • appendChild
  • insertBefore

删除节点 element.removeChild(child)

element.innerHTML

建议仅用于新的节点

  • 内存泄露
  • 安全问题

HTML attribute -> DOM property


HTML属性与DOM对象属性

每个html属性对应相应的DOM对象属性

  • property accessor
  • getAttribute/setAttribute
  • dataset
    • HTMLElement.dataset HTML元素列表上的一个属性
    • data-*属性集
    • 元素上保存数据

CSS -> DOM


window.getComputedStyle() 获取元素的实际样式

var style = window.getComputedStyle(element [, pseudoElt] );

  <input type="text" style="color: red;">

   window.getComputedStyle(element).color;  // " rgb(255,0,0) "
getComputedStyle()

ie9 - 使用element.currentStyle

DOM事件


  • 事件流
  • 事件注册
  • 事件对象
  • 事件分类
  • 事件代理

什么是DOM事件

  • 点击一个DOM元素
  • 键盘按下一个键
  • 输入框输入内容
  • 页面加载完成

DOM 事件流


事件流
  • capture phase 事件捕获
  • target phase 事件触发
  • bubble phase 事件冒泡(某些事件是没有冒泡的,比较页面的load)

事件注册与触发

  • 事件注册
  • 取消事件注册
  • 事件触发

事件注册

eventTarget.addEventListener(type, listener [, useCapture])
最后一个参数 默认是false, 表示获取冒泡过程; true,为获取捕获过程

addEventListener

取消事件注册
eventTarget.removeEventListener( type,listener[,useCapture] )

事件触发
eventTarget.dispatchEvent(type)

 elem.dispatchEvent('click')

浏览器兼容(IE6、7、8)

  • 事件注册与取消
    • attchEvent/detachEvent
  • 事件触发
    • fireEvent(e)
  • no capture (没有捕获阶段)

兼容代码:

事件兼容代码.png

事件对象

  • 属性
    • type
    • target(srcElement)
    • currentTarget
  • 方法
    • stopPropagation 阻止冒泡
    • preventDefault 阻止默认
    • stopImmediatePropagation 也是阻止冒泡,与第一个有区别

阻止事件传播

  • event.stopPropagation() (w3c)
  • event.cancelBubble = true (IE)
  • event.stopImmediatePropagation() ( w3c )
    • 做了第一件事: event.stopPropagation() 阻止事件传播到父节点
    • 第二件事:阻止当前节点的后续事件(一个元素注册多个事件的时候)

默认行为

  • event.preventDefault() ( w3c )
  • event.returnValue = false ( IE )

事件分类


事件分类

** Event **

Event事件

window

  • load 页面加载完成
  • unload 例如点击链接跳转新页面。当前页面会先卸载触发unload事件
  • error 浏览器出现异常时
  • abort 出现取消时

Image

  • load
  • error
  • abort

常用做法:图片加载错误时,加载默认图片

   <image alt='photo' src="./image/a.png" onerror="this.src = 'http://www.163.com/default.jpg' "/>

UIEvent

  • resize
  • scroll
UIEvent

MouseEvent

MouseEvent

MouseEvent对象

  • 属性
    • clientX, clientY 鼠标的位置到页面的最左端,最上端
    • screenX , screenY 鼠标到屏幕的最左端,最上端
    • ctrlKey, shiftKey, altKey, metaKey true/false
    • buttom(0,1,2) 鼠标 左键、中间键、右键

MouseEvent顺序

  • 从元素A上方移过

    • mousemove -> mouseover(A) -> mouseenter (A) -> mousemove (A) -> mouseout (A) -> mouseleave (A)
  • 点击元素

    • mousedown -> [mousemove] -> mouseup -> click

例子 - 拖拽div

  • HTML
    <div id="div1"></div>
  • CSS
  • JS

wheelEvent 滚轮事件

Paste_Image.png

FocusEvent 获得、失去焦点

FocusEvent

FocusEvent

  • 属性
    • relatedTarget 一个元素失去焦点,另外一个元素获得焦点(relatedTarget)

InputEvent

InputEvent
  • beforeinput
  • input

例如:
在输入框输入内容,当输入页面还没显示内容时(触发beforeinput)
在输入框显示自己输入的内容时,触发input,不断地输入内容,不断地触发input事件。

onpropertychange(IE)

keyboardEvent 键盘事件

键盘事件
  • 属性
    • key
    • code
    • ctrlKey、shiftKey、altKey 、metaKey
    • repeat
      用的少:
    • keyCode
    • charCode
    • which

事件代理


  • 优点

    • 需要管理的handler更少
    • 内存分配更少
    • 增加/删除节点可以不处理事件
  • 缺点

    • 事件管理的逻辑更复杂

HTTP


HTTP事务

请求发送过程

请求报文格式

报文

常用HTTP方法

方法

URL 构成

URL

常见HTTP状态码

状态码

Ajax


ajax调用示例

var xhr = new XMLHttpRequest(); //创建XHR对象

//返回处理数据
xhr.onreadystatechange = function(callback){
    if(xhr.readyState == 4){

        if( (xhr.status >= 200 && xhr.status < 300) || shr.status == 304){
            callback( xhr.responseText )
        } else {
            alert('Request was unsuccessful' + xhr.status)
        }
    }
}
xhr.open('get','example.json',true);
xhr.setRequestHeader('myHeader','myValue');//发送请求
xhr.send(null);

open

open

最后一个参数 默认为true 表示异步请求;

请求参加序列化

function serialize(data){
    if(!data) return ''
    var pairs = []
    for (var name in data) {
        if ( !data.hasOwnProperty(name) ) { continue; };
        if( typeof data[name] == 'function'){ continue; };
        
        var value = data[name].toString()
        name = encodeURIComponent(name);
        value = encodeURIComponent(value);
        pairs.push( name + '=' + value )
    };
    return pairs.join('&');
}

同源策略
两个页面拥有相同的协议(protocol),端口(port), 和主机(host), 那么这两个页面就属于同一个源(origin)

同源策略

其他跨域技术

  • frame代理
  • JSONP
  • Comet
  • Web Sockets
  • ......

Frame代理

frame代理流程图

JSONP

  • JSON with padding (填充式json)
  • <script>可以跨域
  • 请求一段js代码
function handleResponse(response){
    alert('my name is ' + response.name);
}

var script = document.createElement('script');
script.src = 'http:127.0.0.1/json?callback=handleResponse'

document.body.insertBefore( script,document.body.firstChild )
json.js返回数据

cookie


作用路径

作用路径

设置/修改

cookie

删除cookie

function removeCookie( name, path, domain ){
    document.cookie = name + '=' 
    + '; path=' + path
    + '; domain=' + domain
    + '; max-age = 0';
}

cookie 的缺陷

  • 流量代价
  • 安全性问题
  • 大小限制 (4kb大小左右)

Storage


  • localStorage
    • 有效期:默认为永久(前提:用户不删除)
  • sessionStorage
    • 有效期:浏览器的会话时间

大小在5MB 左右

作用域也不同;

作用域

js对象

  • 读取
    • localStorage.name
  • 添加/修改
    • localStorage.name = "NetEase" (string)
  • 删除
    • delete localStorage.name

API

  • 获取键值对数量

    • localStorage.length
  • 读取

    • localStorage.getItem(" name "), localStorage.key(i)
  • 添加/修改

    • localStorage.setItem( 'name', 'hello world')
  • 删除对应键值

    • localStorage.removeItem( 'name' )
  • 删除所有数据

    • localStorage.clear()

JS动画


动画实现方式

  • gif
  • flash
  • css3
  • JS

js动画三要素

三要素

setInterval

  var intervalID = setInterva( func, delay [, param1,param2.....])
  clearInterval(intervalID)

setITimeout

setTimeout

requestAnimationFrame

var requestID = requestAnimationFram(Func)
cancelAnimationFrame( requestID )

进度条 实例 setInterval:

 /**
 * [process description]
 * @param  {[type]}   prcsswrap [对象的父元素]
 * @param  {[type]}   drtn      [进度条的时间]
 * @param  {[type]}   intrvl    [定时器时间间隔]
 * @param  {Function} callback  [回调函数]
 */
var process = function(prcsswrap,drtn,intrvl,callback){
    var width = prcsswrap.clientWidth; //clientWidth: 获取对象可见内容的宽度,不包括滚动条,不包括边框;

    //获取对象
    var prcss = prcsswrap.getElementsByClassName('prcss')[0];
    var count = drtn/intrvl; //分成的份数?
    var offset = Math.floor(width/count)
    var tmpCurrent = CURRENT;

    //修改属性值
    var step = function(){
       if(tmpCurrent != CURRENT ){
        prcss.style.width = '0px';
        return;
       }

       var des = getNum( prcss.style.width ) + offset;
       if(des < width){
            prcss.style.width = getNum( prcss.style.width ) + offset
       }else if(des = width ){
            clearInterval(intervalId);
            prcss.style.width = '0px';
            PREV = CURRENT;
            CURRENT = NEXT;
            NEXT++;
            NEXT = NEXT % NUMBER;
            if(callback){
                callback();
            }
       }else{
            prcss.style.width = width + 'px';
       }
       
    };
    var intervalId = setInterval(step,intrvl); //触发定时器
}

进度条 requestAnimationFrame 实例:

requestAnimationFrame

左右移动

左右移动

多媒体编程


多媒体

基本用法

<audio src="music.mp3"></audio>

<video src="movie.mov" width="320" height="320"></video>

audio兼容用法

<audio>
    <source src="music.mp3" type="audio/mpeg">
    <source src="music.wav" type="audio/x-wav">
    <source src="music.ogg" type="audio/ogg">
</audio>

video 兼容用法

video

多媒体格式兼容

是否支持

HTML属性

HTML常用属性

控制多媒体播放

  • load() 加载媒体内容
  • play() 开始播放
  • pause() 暂停播放
  • playbackRate 播放速度
  • currentTime 播放进度
  • volume 音量
  • muted 静音
  • paused 暂停
  • seeking 跳转
  • ended 播放完成
  • duration 媒体时长
  • initialTime 媒体开始时间

多媒体相关事件

  • loadstart 开始请求媒体内容
  • loadmetadata 媒体元数据已经加载完成
  • canplay 加载了一些内容,可以开始播放
  • play 调用play() 或设置了autoplay
  • waiting 缓冲数据不够,播放暂停
  • playing 正在播放

事件列表:

Paste_Image.png

web Audio API

api

canvas


渲染上下文

var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');

globalCompositeOperation 全局组合操作

ctx.globalCompositeOperation = 'destination-over'
组合操作-显示区域

基本绘图的步骤

绘图步骤

实例

地球-月亮-太阳 旋转效果图
var sun = new Image();
var moon = new Image();
var earth = new Image(); 

function init(){
    sun.src = 'sun.png' //new Image的优点是:在给image src赋值那么加载完后会保存在内存中,后面的地方用到就会直接从内存中读取,而不是从网络获取。
    moon.src = 'moon.png'
    earth.src = 'earth.png'
    window.requestAnimationFrame(draw);
}

function draw(){
    ....
}

init();
draw()方法

BOM


代表浏览器窗口的一组api

bom

属性

  • navigator 浏览器信息
  • location 浏览器定位和导航
  • history 窗口浏览器历史
  • screen 屏幕信息

navigator.userAgent

  • chrome

    • "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36"
  • firefox

    • "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:37.0) Gecko/20100101 Firefox/37.0"
  • IE

    • Mozilla/5.0 (Windows NT 6.1; WOW64;Trident/7.0; SLCC2; .NET CLR 2.0.50727;.NET CLR 3.5.....)

location 浏览器定位和导航

location组成
  • assign(url) 载入新的url,记录浏览历史
  • replace(url) 载入新的url,不记录浏览历史
  • reload() 冲在当前页面

history 浏览历史

  • back()
  • forward()
  • go()

screen 屏幕信息

screen

方法

  • alert(), confirm(), prompt() 三种对话框

  • setTimeout(), setInterval() 计时器

  • open(), close() 新开窗口,关闭窗口

    var w = window.open(" subwin.html", "subwin", "width:400,height=350,status=yes,resizable=yes;")

子窗口的关闭

事件

  • load 文档和图片加载完毕时
  • unload 离开当前文档时
  • beforeunload 和unload类似,但它提供询问用户是否确定离开的机会
  • resize 拖动改变浏览器窗口大小时
  • scroll 拖动滚动浏览器时

Form 表单提交


form 属性

  • autocomplete 自动补全(历史下拉记录)on/off


    autocomplete
  • elements 动态节点集合
    • 该表单 子孙表单控件( 除图片按钮 input type="image" )
      表单控件:button , fieldset, input, keygen, object , output, select , textarea.

    • 归属于该表单的表单控件( 除图片按钮 )

实例
  • length elements.length包含节点数的长度
取值实例

form[name]

  • 返回id或name为指定名称的表单控件(除图片按钮外)
  • 如果结果为空,则返回id为指定名称的img元素
  • 如果有多个同名元素,则返回这些元素的动态节点集合
  • 一旦用指定名称取过该元素,则不管该元素的id或name怎么变化,只要节点还在页面上均可使用原名称获取该元素。
取值

form 方法

  • reset()

    • 可重置的元素: input, keygen, output, select, textarea
    • 触发表单reset事件,阻止该事件的默认行为可取消重置
  • submit()

  • checkValidity()

实例:删除文件选择器上选择的文件

label

  • htmlFor
    • 关联表单控件激活行为
    • 可关联元素: buttn, input(除hidden外) ,keygen, meter, output, progress, select, textarea
上传按钮效果

input

  • 本地图片预览
    • onchange
    • accept
      • image/*
      • video/*
      • audio/*
    • multiple
    • files
 <input type="file" accept="image/*" multiple />


file.addEventListener('change',function(event) {
    
var files = Array.prototype.slice.call( event.target.files,0 )
files.forEach(function(item){
        file2dataurl(item,function(){
            var image = new Image();
            parent.appendChild(image);
            image.src = url;
        });
    });
});
代码

select

select

创建选项

  • document.createElement
  • new Option( [ text [, value [,defaultSelected [, selected] ] ] ] );
new option

添加选项

  • insertAdjacentElement
  • select.add
两种方式添加选项

删除选项

  • removeChild
  • select.remove
删除

级联下拉选择器

  • onchange
  • remove
  • add

二级联动实例

HTML代码:

<form action="" name="course">
    <select name="chapter" id="chapter">
        <option>选择章目录</option>
    </select>
    <select name="section" id="">
        <option>选择节目录</option>
    </select>
</form>

JS代码:

var chapters = [
    { text : '1. DOM基础', value : '1' },
    { text : '2. 事件模型', value : '2' }
];

var sections = {
    1 : [
        { text : '1.1 文档树', value : '1.1' },
        { text : '1.2 节点操作', value : '1.2' },
        { text : '1.3 元素遍历', value : '1.3' },
        { text : '1.4 样式操作', value : '1.4' },
        { text : '1.5 属性操作', value : '1.5' },
        { text : '1.6 表单操作', value : '1.6' }
    ],

    2 : [
        { text : '2.1 事件类型', value : '2.1' },
        { text : '2.2 事件模型', value : '2.2' },
        { text : '2.3 事件应用', value : '2.3' }
    ]
};

var forms = document.forms['course'];
var chapterSelect = forms.elements['chapter']
var selectionSelect = forms.elements['section']

//填充select下面的选项
function fillSelect(select,list){
    // console.log(select.length)
    //i > 0  表示不会把第一项删掉
    for (var i = select.length - 1; i > 0; i--) {
        select.remove(i);
    };
    list.forEach(function(data){
        //new Option( [ text [, value [,defaultSelected [, selected] ] ] ] );
        var option = new Option(data.text, data.value);
        select.add(option);
    })
}

fillSelect(chapterSelect,chapters); //初始化章节option

//给章节select添加change事件
chapterSelect.addEventListener('change',function(event){
    var value = event.target.value,
        list = sections[value] || []
    fillSelect(selectionSelect,list);
})

textarea

textarea

textarea
  • selectionEnd 可以设置光标到文本最后的位置

  • selection

textarea selection
  • selectionDirection 主要是 用键盘的shift + 方向建来选择的内容时的行为
    值有:forward控制的是selecitonEnd的位置 , backward 控制selectionStart的位置

@输入提示实例 textarea

  • oninput
  • selectionStart
  • setRangeText
textarea.addEventListener('input',function(event){
    var target = event.target,
        cursor = target.selectionStart;

    if( target.value.charAt(cursor - 1) === '@' ){
        doShowAtList(function(name){
            var end = cursor + name.length;
            target.setRangeText( name, cursor,end,'end');
        })
    }
});

验证

element.

  • willValidate
  • checkValidity()
  • validity
  • validationMessage
  • setCustomValidity(message)

validity

validity

自定义异常

  • oninvalid
  • setCustomValidity

HTML代码:

<form action="./api" name="valid" method="post">
    <p><label for=""> <input name="username" required type="text"></label></p>
    <p><button>submit</button></p>
</form>

JS 代码:

var input = document.forms['valid'].elements['username']
input.addEventListener('invalid',function(event){
    var target = event.target
    if( target.validity.valueMissing ){
        target.setCustomValidity('请输入姓名!')
    }
})
效果图

禁止验证

不希望的结果
<form action="./api" name="valid" novalidate method="post">
    <!-- 选择type=number 目的是在手机上可以唤起数字键盘 -->
    <p> <input type="number" name="tel"></p>
    <p><button>submit</button></p>
</form>

novalidate 禁止表单提交的时候做验证

隐式提交

  • 如: 聚焦在输入框时按回车提交表单
  • 满足一下任一条件:
    • 表单有非禁用的提交按钮;
    • 没有提交按钮时,不超过一个类型为:text, search, url, email, password, date,time, number的input元素
有非禁用的提交按钮

** 表单提交过程**

  • 根据表单 enctype 指定的值构建要提交的数据结构
  • 使用 method 指定的方式发送数据岛action指定的目标

** 编码方式(enctype)**

  • application/x-www-form-urlencoded [默认]
  • multipart/form-data
  • text/plain

特殊案例

  • name = "isindex" && type="text"
    • 编码方式为 application/x-www-form-urlencoded
    • 作为表单的第一个提交元素
    • 提交时只发送value值,不包含name
eg
  • name = "charset" && type="hidden"
    • 如果没有设置value值
    • 提交时value自动用当前提交的字符集填充
特殊案例

submit()

  • 提交表单
    form.submit()
  • onsubmit
    • 表单提交事件
    • 提交之前的数据验证
    • 阻止事件的默认行为可取消
修改提交

无刷新表单提交

  • form
  • target
  • iframe
用iframe提交表单

代码:

<iframe name="targetFrame" class="f-hidden"></iframe>
<form action="./api" name="fom" method="post" target="targetFrame">
    <input name="a"/>
    <input name="b"/>
    <input name="c"/>
    <button>submit</button>
</form>  

iframe 处理服务端返回的结果代码:

var form = document.forms.fom;
var frame = document.getElementById('result');
frame.addEventListener('load',function(){
    try{
        var result = JSON.parse( frame.contentWindow.document.body.textContent );
        //还原登录按钮状态
        disableSubmit(false); // 自定义方法
        //识别登录结果
        
        console.log(result)
        
        if( result.code === 200 ){
            showMessage('j-suc','登录成功'); // 自定义方法,提示信息
            form.reset();
        }

    }catch(ex){
        console.log(ex);
    }
})

function disableSubmit(bool){
    //修改按钮状态
}
function showMessage(cls,msg){
    //提示信息显示
}

列表


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • element.chidren和element.childNodes的区别 element.children是El...
    cheerss阅读 446评论 0 1
  • 一、样式篇 第1章 初识jQuery (1)环境搭建 进入官方网站获取最新的版本 http://jquery.co...
    凛0_0阅读 3,350评论 0 44
  • 营销和运营的前提是所做的产品,在正确的方向(市场所需求的产品-解决客户的痛点问题)。 内容创意两个方向: 做内容、...
    木木南子阅读 133评论 0 0
  • 我发现写作是一件多么愉快的事情,所有的情绪都通过文字传递出去了。情感的共鸣就此产生,而言语总是让我腹背受敌。直接...
    怜月戈阅读 169评论 0 0
  • 作者:李米 (一) 我是一个侗族姑娘,但是我从未穿起过我那套和市面上花布衣裳不一样的成年装,一如我不会讲侗族的语言...
    丘比的书桌阅读 496评论 0 2