xiaocao-dating/app.js · 约 12868 字符
1
2(function(){
3 var D = window.DATA;
4 var page = document.body.getAttribute('data-page');
5 function toast(m){var t=document.getElementById('toast');if(!t)return;t.textContent=m;t.classList.add('show');setTimeout(function(){t.classList.remove('show')},1400);}
6 function esc(s){return String(s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c]});}
7 // 底部导航高亮
8 if(page){
9 var nav=document.querySelector('.nav a[data-nav="'+page+'"]');
10 if(nav)nav.classList.add('on');
11 }
12
13 /* ========== 首页滑卡 ========== */
14 if(page==='home'){
15 var pool = D.users.slice();
16 var deck = document.getElementById('deck');
17 var emptyEl = document.getElementById('empty');
18 var leftEl = document.getElementById('left');
19 var total = pool.length;
20 function render(){
21 deck.innerHTML='';
22 var show = pool.slice(0,3).reverse();
23 show.forEach(function(u,i){
24 var idx = show.length-1-i;
25 var c = document.createElement('div');
26 c.className='card';
27 c.style.zIndex = idx;
28 c.style.transform = 'scale('+(1-idx*0.05)+') translateY('+(idx*14)+'px)';
29 c.setAttribute('data-id',u.id);
30 var tags = u.tags.map(function(t){return '<span class="tag">'+esc(t)+'</span>';}).join('');
31 c.innerHTML =
32 '<div class="photo" style="background:'+u.grad+'">'+u.emoji+'</div>'+
33 '<div class="scrim"></div>'+
34 '<div class="decision like">心动</div><div class="decision nope">跳过</div>'+
35 '<div class="info"><div class="nm">'+esc(u.name)+' <span>'+u.age+'岁</span>'+
36 (u.verified?'<span class="vbadge">✔ 真人</span>':'')+'</div>'+
37 '<div class="jb">'+esc(u.job)+'</div>'+
38 '<div class="meta">📍 '+esc(u.dist)+' · 在线</div>'+
39 '<div class="tags">'+tags+'</div>'+
40 '<div style="font-size:13px;opacity:.92">'+esc(u.bio)+'</div></div>';
41 deck.appendChild(c);
42 if(idx===0) bindDrag(c,u);
43 });
44 leftEl.textContent = '今日剩余心动 ' + pool.length + ' 位';
45 if(pool.length===0){emptyEl.style.display='flex';deck.style.display='none';document.querySelector('.actbar').style.display='none';}
46 }
47 function like(u,c){
48 if(!c)return;
49 var lk=c.querySelector('.decision.like'); if(lk)lk.style.opacity=1;
50 c.style.transform='translate(120%,-40px) rotate(22deg)'; c.style.opacity=0;
51 setTimeout(function(){pool.shift();render(); showMatch(u);},330);
52 }
53 function nope(u,c){
54 if(!c)return;
55 var n=c.querySelector('.decision.nope'); if(n)n.style.opacity=1;
56 c.style.transform='translate(-120%,-40px) rotate(-22deg)'; c.style.opacity=0;
57 setTimeout(function(){pool.shift();render();},330);
58 }
59 function showMatch(u){
60 var m=document.getElementById('match');
61 document.getElementById('matchName').textContent=u.name;
62 document.getElementById('matchEmoji').textContent=u.emoji;
63 m.classList.add('show');
64 }
65 function bindDrag(c,u){
66 var sx=0,sy=0,dragging=false;
67 function down(e){dragging=true;var p=e.touches?e.touches[0]:e;sx=p.clientX;sy=p.clientY;c.style.transition='none';}
68 function move(e){if(!dragging)return;var p=e.touches?e.touches[0]:e;var dx=p.clientX-sx,dy=p.clientY-sy;
69 c.style.transform='translate('+dx+'px,'+dy+'px) rotate('+(dx/18)+'deg)';
70 var lk=c.querySelector('.decision.like'),np=c.querySelector('.decision.nope');
71 if(lk)lk.style.opacity=dx>40?Math.min(1,dx/90):0;
72 if(np)np.style.opacity=dx<-40?Math.min(1,-dx/90):0;
73 if(e.cancelable)e.preventDefault();}
74 function up(e){if(!dragging)return;dragging=false;c.style.transition='';var p=(e.changedTouches?e.changedTouches[0]:e);
75 var dx=p.clientX-sx;
76 if(dx>90)like(u,c); else if(dx<-90)nope(u,c);
77 else{c.style.transform='';var lk=c.querySelector('.decision.like'),np=c.querySelector('.decision.nope');if(lk)lk.style.opacity=0;if(np)np.style.opacity=0;}}
78 c.addEventListener('mousedown',down);window.addEventListener('mousemove',move);window.addEventListener('mouseup',up);
79 c.addEventListener('touchstart',down,{passive:true});c.addEventListener('touchmove',move,{passive:false});c.addEventListener('touchend',up);
80 }
81 document.getElementById('btnLike').onclick=function(){var c=deck.querySelector('.card');if(c)like(pool[0],c);};
82 document.getElementById('btnNope').onclick=function(){var c=deck.querySelector('.card');if(c)nope(pool[0],c);};
83 document.getElementById('btnStar').onclick=function(){toast('已超级喜欢 ⭐ 会优先被看到');};
84 document.getElementById('matchClose').onclick=function(){document.getElementById('match').classList.remove('show');};
85 render();
86 }
87
88 /* ========== 灵魂测试 ========== */
89 if(page==='soul'){
90 var qi=0, tally={};
91 var qs=D.soul.questions;
92 var step=document.getElementById('step');
93 var prog=document.getElementById('prog');
94 var qtext=document.getElementById('qtext');
95 var opts=document.getElementById('opts');
96 var intro=document.getElementById('intro');
97 var quiz=document.getElementById('quiz');
98 var result=document.getElementById('result');
99 function start(){intro.style.display='none';quiz.style.display='block';showQ();}
100 function showQ(){
101 prog.style.width=((qi)/qs.length*100)+'%';
102 step.textContent='第 '+(qi+1)+' / '+qs.length+' 题';
103 qtext.textContent=qs[qi].q;
104 opts.innerHTML='';
105 qs[qi].options.forEach(function(o){
106 var b=document.createElement('button');b.className='opt';b.textContent=o.t;
107 b.onclick=function(){tally[o.type]=(tally[o.type]||0)+1;qi++;
108 if(qi<qs.length){prog.style.width=(qi/qs.length*100)+'%';showQ();} else showRes();};
109 opts.appendChild(b);
110 });
111 }
112 function showRes(){
113 quiz.style.display='none';result.style.display='block';
114 var best='calm',max=0;for(var k in tally){if(tally[k]>max){max=tally[k];best=k;}}
115 var r=D.soul.results[best];
116 document.getElementById('resBadge').style.background=r.grad;
117 document.getElementById('resEmoji').textContent=r.emoji;
118 document.getElementById('resName').textContent=r.name;
119 document.getElementById('resDesc').textContent=r.desc;
120 var rec=document.getElementById('rec');
121 rec.innerHTML='';
122 D.users.slice(0,3).forEach(function(u){
123 var c=document.createElement('div');c.className='msg glass';
124 c.innerHTML='<div class="av" style="background:'+u.grad+'">'+u.emoji+'</div>'+
125 '<div class="bd"><div class="t">'+esc(u.name)+' <span>'+u.age+'岁</span></div>'+
126 '<div class="l">'+esc(u.tags.join(' · '))+'</div></div>'+
127 '<div class="tm">同频</div>';
128 c.onclick=function(){toast('已向 '+u.name+' 发起灵魂对话 💬');};
129 rec.appendChild(c);
130 });
131 }
132 document.getElementById('startQuiz').onclick=start;
133 document.getElementById('retake').onclick=function(){qi=0;tally={};result.style.display='none';intro.style.display='block';};
134 }
135
136 /* ========== 搭子广场 ========== */
137 if(page==='dazi'){
138 var scene=document.getElementById('scenes');
139 var list=document.getElementById('list');
140 var cur='全部';
141 var posts=D.dazi.posts.slice();
142 D.dazi.scenes.forEach(function(s){
143 var c=document.createElement('span');c.className='chip'+(s==='全部'?' on':'');c.textContent=s;
144 c.onclick=function(){cur=s;[].forEach.call(scene.children,function(x){x.classList.remove('on');});c.classList.add('on');render();};
145 scene.appendChild(c);
146 });
147 function render(){
148 list.innerHTML='';
149 var f=posts.filter(function(p){return cur==='全部'||p.scene===cur;});
150 if(!f.length){list.innerHTML='<div class="card-hint">该场景下还没有搭子,去发起一个吧~</div>';return;}
151 f.forEach(function(p){
152 var el=document.createElement('div');el.className='post glass';
153 el.innerHTML='<div class="ph"><div class="av" style="background:'+p.grad+'">'+p.emoji+'</div>'+
154 '<div class="who"><b>'+esc(p.user)+'</b> · '+esc(p.scene)+'<div>'+esc(p.dist)+' · '+esc(p.time)+'</div></div></div>'+
155 '<h3>'+esc(p.title)+'</h3><div class="de">'+esc(p.desc)+'</div>'+
156 '<div class="ft"><div class="left">已有 '+p.joined+' 人加入</div><div class="join">加入搭子</div></div>';
157 var jb=el.querySelector('.join');
158 jb.onclick=function(){if(jb.classList.contains('done'))return;jb.classList.add('done');jb.textContent='已加入 ✓';p.joined++;toast('已加入「'+p.title+'」搭子群 🎉');};
159 list.appendChild(el);
160 });
161 }
162 render();
163 // 发起搭子
164 var modal=document.getElementById('daziModal');
165 document.getElementById('openDazi').onclick=function(){modal.classList.add('show');};
166 document.getElementById('closeDazi').onclick=function(){modal.classList.remove('show');};
167 document.getElementById('submitDazi').onclick=function(){
168 var title=document.getElementById('dTitle').value.trim();
169 var desc=document.getElementById('dDesc').value.trim();
170 var sc=document.getElementById('dScene').value;
171 var emojis={'饭搭子':'🍜','旅游搭子':'🧳','运动搭子':'🏃','学习搭子':'📚','游戏搭子':'🎮','电影搭子':'🎬'};
172 if(!title||!desc){toast('请填写标题和描述');return;}
173 posts.unshift({scene:sc,title:title,desc:desc,user:'我',time:'刚刚',dist:'0m',joined:1,
174 emoji:emojis[sc]||'✨',grad:'linear-gradient(135deg,#ff4d8d,#8b5cf6)'});
175 modal.classList.remove('show');
176 document.getElementById('dTitle').value='';document.getElementById('dDesc').value='';
177 cur='全部';[].forEach.call(scene.children,function(x,i){x.classList.toggle('on',i===0);});
178 render();toast('搭子已发布,等待同频的人加入 🎉');
179 };
180 }
181
182 /* ========== 动态 ========== */
183 if(page==='moments'){
184 var list=document.getElementById('list');
185 function render(){
186 list.innerHTML='';
187 D.moments.forEach(function(m,i){
188 var el=document.createElement('div');el.className='moment glass';
189 el.innerHTML='<div class="hd"><div class="av" style="background:'+m.grad+'">'+m.emoji+'</div>'+
190 '<div><div class="nm">'+esc(m.user)+'</div><div class="tm">'+esc(m.time)+'</div></div></div>'+
191 '<div class="ct">'+esc(m.content)+'</div>'+
192 '<div class="img" style="background:'+m.img+'"></div>'+
193 '<div class="ft"><div class="lk" data-i="'+i+'">❤ <span>'+m.likes+'</span></div>'+
194 '<div>💬 '+m.comments+'</div></div>';
195 var lk=el.querySelector('.lk');
196 if(m.liked)lk.classList.add('on');
197 lk.onclick=function(){m.liked=!m.liked;m.likes+=m.liked?1:-1;lk.classList.toggle('on');lk.querySelector('span').textContent=m.likes;};
198 list.appendChild(el);
199 });
200 }
201 render();
202 }
203
204 /* ========== 我的 ========== */
205 if(page==='mine'){
206 var p=D.profile;
207 document.getElementById('pAvatar').style.background=p.grad;
208 document.getElementById('pAvatar').textContent=p.emoji;
209 document.getElementById('pName').innerHTML=esc(p.name)+' <span class="vbadge">✔ 真人</span>'+(p.vip?' <span class="vbadge" style="color:#ffd86b;border-color:rgba(255,216,107,.4);background:rgba(255,216,107,.12)">VIP</span>':'');
210 document.getElementById('pJob').textContent=p.age+'岁 · '+esc(p.job)+' · '+esc(p.city);
211 document.getElementById('pBio').textContent=p.bio;
212 document.getElementById('sLike').textContent=p.stats.like;
213 document.getElementById('sMatch').textContent=p.stats.match;
214 document.getElementById('sDazi').textContent=p.stats.dazi;
215 var msgList=document.getElementById('msgs');
216 D.matches.forEach(function(m){
217 var el=document.createElement('div');el.className='msg glass';
218 el.innerHTML='<div class="av" style="background:'+m.grad+'">'+m.emoji+'</div>'+
219 '<div class="bd"><div class="t">'+esc(m.name)+(m.verified?' <span class="vbadge">✔</span>':'')+'</div>'+
220 '<div class="l">'+esc(m.last)+'</div></div><div class="tm">'+esc(m.time)+'</div>';
221 el.onclick=function(){toast('打开与 '+m.name+' 的聊天 💬');};
222 msgList.appendChild(el);
223 });
224 [].forEach.call(document.querySelectorAll('.menu .it'),function(it){
225 it.onclick=function(){toast(it.querySelector('.tx').textContent+' · 演示功能');};
226 });
227 }
228
229 /* 通用:点 logo 回首页 */
230 var logo=document.querySelector('.brand');
231 if(logo && page!=='home'){logo.onclick=function(){location.href='index.html';};}
232})();
233