全部文章

<p>本文假设你已经看过并熟悉了<a href="https://zhuanlan.zhihu.com/p/68527022">参考文章</a> </p> <p>其他和参考文章的都一样,我就不赘述了。建议先看参考文章。</p> <p>我遇到的问题是,在两个及以上组件使用装饰器会出现问题,具体就是找不到属性或方法。</p> <h2>使用</h2> <pre><code>export class ChatPanelComponent extends MessageListenersManager { constructor(wsMessageService: WsMessageService) { super(wsMessageService); } @MessageListener(Receive.SingleChatMessage) onSingleChatMessageRead(message: SingleChatMessage) { console.log('[ChatPanelComponent][onSingleChatMessageRead]: ', message); this.pushMessageToChatPanel(message); } }</code></pre> <h3>出错信息如下</h3> <pre><code>core.js:15724 ERROR TypeError: this.pushMessageToChatPanel is not a function at ClientComponent.push../src/client/shared/components/chat-panel/chat-panel.component.ts.ChatPanelComponent.onTaskChatMessage (chat-panel.component.ts:132) at SafeSubscriber._next (message-listener.ts:29) at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:194) at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (Subscriber.js:132) at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76) at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53) at TakeUntilSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76) at TakeUntilSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53) at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41) at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53)</code></pre> <p><code>pushMessageToChatPanel</code> 在组件 <code>chat-panel.component.ts</code> 上是存在 ,很显然是 <code>this</code> 的指向问题。 既然知道是 <code>this</code> 指向的问题,那么就让 <code>this</code> 指向就好了。</p> <p>思路:在装饰器中把一个数组压入 <code>__messageListeners__</code>,数组第一个元素是组件的 <code>constructor</code>,第二个是函数</p> <h3>解决方法</h3> <ol> <li> <p>改装饰器</p> <pre><code>import { MessageReceiveData } from '@client/core/models/ws-message.model'; import { takeUntil } from 'rxjs/operators'; import { MessageListenersManager } from './message-listeners-manager'; export type ReceiveArgumentsType<T extends keyof MessageReceiveData> = MessageReceiveData[T] extends undefined ? () => void : (data?: MessageReceiveData[T]) => void; export function MessageListener<T extends keyof MessageReceiveData>(type: T) { return ( target: MessageListenersManager, propertyKey: string, descriptor: TypedPropertyDescriptor<ReceiveArgumentsType<T>>, ) => { // 获取构造上的静态属性 __messageListeners__ const constructor = Object.getPrototypeOf(target).constructor; if (constructor && constructor.__messageListeners__) { // 将创建订阅的方法推入 __messageListeners__ , 以便在构造时调用 constructor.__messageListeners__.push([target.constructor, function () { // 创建指定类型的订阅 this.wsMessageService .receive(type) // 使用 takeUntil 操作符以便自动取消订阅 .pipe(takeUntil(this.__messageListenersTakeUntilDestroy$__)) .subscribe((data) => { // 收到返回后调用被装饰得方法 descriptor.value.call(this, data); }); }]); } return descriptor; }; }</code></pre> </li> <li> <p>改管事件理器</p> <pre><code>import { OnDestroy } from '@angular/core'; import { WsMessageService } from '@client/core'; import { Subject } from 'rxjs'; export class MessageListenersManager implements OnDestroy { static __messageListeners__: [any, Function][] = []; readonly __messageListenersTakeUntilDestroy$__ = new Subject<void>(); constructor(public wsMessageService: WsMessageService) { MessageListenersManager.__messageListeners__.forEach((item) => { const [ctr, fun] = item; if (this instanceof ctr) { const index = MessageListenersManager.__messageListeners__.findIndex(a => a == item); if (index > -1) { // console.log(`${index} matched:, ${key.name}`); fun.apply(this); // MessageListenersManager.__messageListeners__.splice(index, 1); } } }); } ngOnDestroy(): void { this.__messageListenersTakeUntilDestroy$__.next(); this.__messageListenersTakeUntilDestroy$__.complete(); } }</code></pre> </li> </ol> <p>以上的解决方法虽不是很优雅,读起来也有点苦涩,但好在能解决我的问题,如果有更好的解决方法,欢迎<a href="https://zhuanlan.zhihu.com/p/68527022">回复</a>。</p> <h2>参考</h2> <p><a href="https://zhuanlan.zhihu.com/p/68527022">使用 Typescript 构建类型安全的 Websocket 应用</a></p>
详情
<h2>按楼层名称排序</h2> <p>昨天接到一个需求,如下: 一个乱序的楼层数组</p> <pre><code class="language-javascript">[ '7D', '7A', '15A', '19B', '9D', '8B', '16A', '21B', '11D', '15C', '10B', '12A', '15B', '14C', '16D', '10A', '7C', '16C', '16B', '17C', '8D', '19A', '17B', '11B', '21A', '14D', '21C', '14B', '20C', '11A', '20D', '20A', '12D', '18B', '14A', '9A', '20B', '8C', '10C', '18D', '7B', '8A', '19D', '11C', '19C', '18C', '9C', '10D', '18A', '12B', '15D', '17A', '17D', '12C', '9B' ]</code></pre> <p>排序后的结果要求是:</p> <pre><code class="language-javascript">[ '7A', '7B', '7C', '7D', '8A', '8B', '8C', '8D', '9A', '9B', '9C', '9D', '10A', '10B', '10C', '10D', '11A', '11B', '11C', '11D', '12A', '12B', '12C', '12D', '14A', '14B', '14C', '14D', '15A', '15B', '15C', '15D', '16A', '16B', '16C', '16D', '17A', '17B', '17C', '17D', '18A', '18B', '18C', '18D', '19A', '19B', '19C', '19D', '20A', '20B', '20C', '20D', '21A', '21B', '21C' ]</code></pre> <p>我的的实现,借助 <code>loadsh</code> 的 <code>sortBy</code> 函数,先按数字排,然后再按字母排。 完整代码如下:</p> <pre><code class="language-javascript">const _ = require('loadsh'); let zoneNames = [ '15B', '7C', '11D', '14D', '18B', '14A', '12C', '8C', '16B', '16C', '17B', '17D', '14C', '21C', '20D', '10C', '17A', '9A', '10B', '21A', '19C', '12D', '9D', '15A', '11A', '18A', '14B', '20B', '10A', '18D', '7A', '15C', '9B', '11B', '19A', '16A', '11C', '16D', '19D', '7B', '20C', '21B', '10D', '18C', '12A', '19B', '8B', '20A', '8D', '17C', '15D', '8A', '7D', '9C', '12B' ] zoneNames = _.shuffle(zoneNames); console.log('before sort:', zoneNames); const sortedZoneNames = _.sortBy(zoneNames, function (floor) { const name = floor || ''; return parseInt(name, 10); }, function (floor) { let name = floor || ''; name = name.replace(/[0-9]/g, ''); return name; }, ); console.log('after sort:', sortedZoneNames);</code></pre> <p>以上,纯属记录一下。88。</p>
详情
<p>手贱升级了 <code>Android Studio</code>,也升级 <code>Android Gradle 插件</code> 然而执行</p> <pre><code class="language-bash">flutter run</code></pre> <p>报错了: <code>Minimum supported Gradle version is 6.5. Current version is 6.4.1.</code></p> <p>搜索找到了问题所在: 两个版本不匹配。</p> <p>分析第一句: <code>Minimum supported Gradle version is 6.5.</code> 哪个版本和哪个版本对比? 找到 <code>android 项目/build.gradle 文件</code></p> <pre><code>buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.1.0' } }</code></pre> <p>如上,<code>4.1.0</code> 是 <code>Android Gradle 插件</code>的版本 <a href="https://developer.android.google.cn/studio/releases/gradle-plugin.html">查对应关系</a> 发现</p> <pre><code>4.1.0+ -> 6.5+</code></pre> <p>翻译过来就是 <code>Android Gradle 插件</code>从 <code>4.1.0</code> 开始,需要 <code>Gradle</code> 最低的版本为 <code>6.5</code>。</p> <p>理解了第一句的错误提示之后,那么,如果查看 <code>Gradle</code> 的版本呢? 打开 <code>android 项目/gradle/wrapper/gradle-wrapper.properties</code> 看 <code>distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip</code> 匹配上 <code>Current version is 6.4.1</code></p> <p>理解 Android Gradle 版本和 Gradle 版本的对应关系之后,问题就很容易解决了。 两个方向</p> <p>一、改 Android Gradle 的版本,例如我的改成如下</p> <pre><code>// android 项目/build.gradle buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.0.0' } }</code></pre> <p>二、改 Gradle 的版本。 如</p> <pre><code>// android 项目/gradle/wrapper/gradle-wrapper.properties distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip</code></pre> <p>下载 gradle 会很慢,请做好心理准备。</p> <p>2021-04-03 补充:</p> <p>问:如何解决国内下载 gradle zip 包越来越慢的问题?</p> <p>答:困扰我多日的麻烦,经探索,我得出的办法是用迅雷下载:<code>https://services.gradle.org/distributions/gradle-6.4.1-all.zip</code></p> <p>2024-09-08 补充:</p> <p>答上一个问题:使用国内镜像,如:<code>mirrors.cloud.tencent.com/gradle/</code>。比如例子中的完整地址是:<code>https://mirrors.cloud.tencent.com/gradle/gradle-6.4.1-all.zip</code></p>
详情
<h1>悦阅 app</h1> <p>框图 <img src="//www.pcdeng.com/uploads/yueyue-app.png" alt="框图" /> 完成的功能点有:</p> <ul> <li>下拉刷新。</li> <li>滑到到底部加载更多</li> <li>加载状态</li> </ul> <p>悦阅 app Android app 已经开发完毕,如果你想体验,可以通过这里下载 <a href="http://img.qulang8.com/YueYue.apk">悦阅 apk</a></p> <h2>学到的</h2> <h3>Dart 基础</h3> <p><img src="//www.pcdeng.com/uploads/dart-basic.png" alt="Dart 基础" /></p> <h3>存储</h3> <p>用的包是 <code>shared_preferences</code> 基础用法</p> <ul> <li>安装</li> </ul> <p>在 <code>pubspec.yaml</code> 文件的 <code>dependencies</code> 段添加 <code>shared_preferences: "^0.4.2"</code> 依赖。</p> <ul> <li> <p>封装</p> <pre><code class="language-dart">class LocalStorage { static save(String key, value) async { SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString(key, value); } static get(String key) async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.get(key); } static remove(String key) async { SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.remove(key); } }</code></pre> </li> </ul> <h3>Redux</h3> <p>这有一部分花了比较多时间,基本都是调试出来的,对我来说,最难的是如何获得 store 的实例。我还没有理清楚它内部的实现,只知道如何使用,而且使用的方法可能不太优雅,看起来是这样的。 第一步:添加依赖 在 <code>pubspec.yaml</code> 文件的 <code>dependencies</code> 段,添加</p> <pre><code>redux: ^3.0.0 flutter_redux: ^0.5.3</code></pre> <p>第二步:初始化</p> <pre><code>void main() async { final store = new Store<UserState>( appReducer, initialState: UserState.initState( isLogin: false, email: '', accessToken: '', ), ); runApp(MyApp( store: store, )); }</code></pre> <p>第三步:在 Widget 中使用</p> <pre><code>@override Widget build(BuildContext context) { return StoreConnector<UserState, UserState>( converter: (store) => store.state, builder: (context, state) { if (state != null && state.isLogin) { return _userInfo(state); } return _loginButton(context); }, ); }</code></pre> <h3>页面的常用布局。</h3> <ul> <li>Container</li> <li>Row,</li> <li>Expanded</li> <li>Column</li> <li>Card</li> <li>Image</li> <li>Padding</li> <li>Align</li> </ul> <h3>事件</h3> <ul> <li>GestureDetector</li> </ul>
详情
<h1>京东京造 K2</h1> <p>今年 618 美其名曰“送自己一个生日礼物”,本想买游戏机,无奈太贵,不舍得,所以折中了买了个机械键盘。之前有关注过 Keychron,无奈购买麻烦,只能舍弃。最终选择了京东京造 K2,和 Keychron 长好像,或许就是同一个。我也不关心它们两者的关系的,399 这个价,还可以接受就入手了。 先来看看它的样子。<img src="https://img14.360buyimg.com/n0/jfs/t1/117592/2/8272/295270/5ecdfe18E91d776dd/3218d27f408325d1.jpg" alt="" /> 拿到手,首先就是开蓝牙,连上笔记本。 “模式切换”切换拔到 BT 位置,然后按 Fn + 1,然后打开笔记本蓝牙,选择 Keychron K2 瞬间连上。之后就来愉快地敲打吧。</p> <p>感觉,太高了。得买个键盘托,不然肩很容易累。 跟同事一千的多键盘比起来还是有很大差距的,但足够我用了,毕竟可以装一下,它的颜值还是可以滴。 好了,玩几天之后再来更新。我去发朋友圈了。</p>
详情
<h1></h1> <p>从今天开始,开始整理以前做过的项目,把一些自己认为做得不错的项目一一总结。</p> <h2>悦阅 app</h2> <p><a href="https://www.pcdeng.com/yueyue-apk.html">https://www.pcdeng.com/yueyue-apk.html</a></p>
详情
<h1>Isotope</h1> <p>Isotope 是一个布局、排序、过滤带有很牛的动画效果的 js 库。最近有一个项目,老板要求用它的动画效果。一时半会用 angular 也没办法模拟出同样的效果,所以就研究了一下 isotope,并顺手写一个小例子来学一下怎样使用 isotope。</p> <p>以下是项目需要实现的效果:</p> <p><img src="//www.pcdeng.com/uploads/isotope-demo.gif" alt="Isotope" /></p> <p><a href="https://pcdeng.github.io/components/isotope/isotope-demo.html">demo 地址</a></p> <h2>参考</h2> <p><a href="https://isotope.metafizzy.co/">Isotope</a></p>
详情
<h2>需求</h2> <p>最近工作遇到要实现纯的背景色的长度要按百分比算。 如图:<img src="//www.pcdeng.com/uploads/task.svg" alt="task" /></p> <pre><code class="language-html"><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Task item</title> <style> .task { width: 100%; height: 50px; background: linear-gradient(90deg, #e7791e 90%, transparent 0%); border: 1px solid #000; display: flex; justify-content: space-between; align-items: center; padding: 2px 4px; box-sizing: border-box; } .l1 { color: #fff; } </style> </head> <body> <div class="task"> <div> <h3 class="l1"> <span>4306</span> <span>VD</span> <span>Arr</span> </h3> </div> <div>actions</div> </div> </body> </html></code></pre> <p>关键的点是</p> <pre><code class="language-css">background: linear-gradient(90deg, #e7791e 90%, transparent 0%);</code></pre> <h2>参考</h2> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/linear-gradient">linear-gradient</a></p>
详情
<p>背景: Ionic 项目,要实现通知栏常驻,就是只要 app 活着,顶部通知栏就要显示“XXX 正在运行中”。 其中涉及 Android 中的两个主要概念。 <code>Service</code> 和 <code>Notification</code> 修改的文件涉及三个</p> <h2>一、应用的清单文件(<code>AndroidManifest.xml</code>)</h2> <p>要用 service 必须要在 <code>AndroidManifest.xml</code> 中声明,我就踩进这个坑了,半天才爬出来。总结:给点耐心多看官方文档。</p> <pre><code class="language-xml"><manifest ... > ... <application ... > <service android:name=".MyService" /> ... </application> </manifest></code></pre> <h2>二、MyService</h2> <p>不知道说啥好,直接看代码,引入的就不放上来了,用 IDE 解决,缺少什么就引入什么。特别注意的是 Android 8 之后增加 NotificationChannel,要注意兼容,详情请看<a href="https://developer.android.google.cn/guide/topics/ui/notifiers/notifications">通知概览</a></p> <pre><code>public class MyService extends Service { private NotificationManager notificationManager; private String notificationId = "stickyChannelId"; private String notificationName = "Sticky Channel"; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // 创建NotificationChannel if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } startForeground(1, getNotification()); } private Notification getNotification() { Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("测试服务") .setOngoing(true) .setContentText("我正在运行"); // 设置Notification的ChannelID,否则不能正常显示 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(notificationId); } Notification notification = builder.build(); return notification; } }</code></pre> <h2>三、使用</h2> <p>还是直接上代码吧,注释也做了说明了。 简单来说就是 <code>onCreate</code> 中调用 <code>startService</code> 或者 <code>startForegroundService</code> 把这个 <code>service</code> 进入前台服务(保活)。 在 <code>onDestroy</code> 回调停止服务</p> <pre><code class="language-java">public class MainActivity extends CordovaActivity { private Intent mServiceIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // enable Cordova apps to be started in the background Bundle extras = getIntent().getExtras(); if (extras != null && extras.getBoolean("cdvStartInBackground", false)) { moveTaskToBack(true); } // Set by <content src="index.html" /> in config.xml loadUrl(launchUrl); if (mServiceIntent == null) { mServiceIntent = new Intent(MainActivity.this, MyService.class); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // android8.0 以上通过 startForegroundService 启动 service startForegroundService(mServiceIntent); } else { startService(mServiceIntent); } } /** * The final call you receive before your activity is destroyed. */ @Override public void onDestroy() { if (mServiceIntent != null) { this.stopService(mServiceIntent); } super.onDestroy(); } }</code></pre> <h2>注意:</h2> <pre><code>defaultBuildToolsVersion="28.0.3" defaultMinSdkVersion=19 defaultTargetSdkVersion=23 // 如果设为 26,常驻通知栏就不显示了。原因不明。 defaultCompileSdkVersion=28</code></pre> <h2>参考:</h2> <ul> <li><a href="https://blog.csdn.net/huaheshangxo/article/details/82856388">Android 8.0中Service和Notification</a></li> <li><a href="https://developer.android.google.cn/guide/components/services">Service服务概览</a></li> <li><a href="https://blog.csdn.net/xy_nyle/article/details/19853591">Android 弹无虚发之第四弹</a></li> </ul>
详情
<h2>一、下载你需要的 SVG 图标</h2> <p>去<a href="https://www.iconfont.cn/search">Iconfont</a>搜索你想要的图标。例如,我搜索 <code>download</code> 并下载了 <code>download.svg</code></p> <h2>二、放到 /src/assets/abc/下</h2> <p>把下载好的 <code>download.svg</code> 放到 <code>/src/assets/abc</code> 注意 <code>abc</code> 就是一个命名空间。</p> <blockquote> <p>动态引入,只需要保证 SVG 资源文件放到了相应的目录,即 assets/${namespace} 即可。例如你在 zoo 命名空间下有一个 panda 图标,你需要做的就是将 panda.svg 放到 assets/zoo 目录底下。</p> </blockquote> <h2>三、使用图标</h2> <pre><code class="language-html"><i nz-icon nzType="abc:download"></i> <!-- abc是命名空间,download 对应 download.svg --></code></pre> <h2>四、参考</h2> <p><a href="https://ng.ant.design/components/icon/zh">图标 Icon</a></p>
详情
<h1>Git 常用命令汇总</h1> <h2>一、Git 工作原理图</h2> <p><img src="//www.pcdeng.com/uploads/git-flow.png" alt="Git工作原理图" /></p> <h2>二、常用命令</h2> <ul> <li> <p>查看远程分支</p> <pre><code class="language-sh">git branch -a</code></pre> </li> <li> <p>查看本地分支</p> <pre><code class="language-sh">git branch</code></pre> </li> <li> <p>切换到<code>test</code>分支</p> <pre><code class="language-sh">git checkout test</code></pre> </li> <li> <p>创建<code>test</code>分支</p> <pre><code>git branch test</code></pre> </li> <li> <p>删除本地<code>test</code>分支</p> <pre><code class="language-sh">git branch -d test</code></pre> </li> <li> <p>推送<code>test</code>分支到远程服务器</p> <pre><code>git push origin test</code></pre> </li> <li> <p>添加<code>db</code>文件夹</p> <pre><code class="language-sh">git add db</code></pre> </li> <li> <p>提交信息</p> <pre><code class="language-sh">git commit -m '添加db文件夹'</code></pre> </li> <li> <p>将提交推送到远程<code>test</code>分支</p> <pre><code class="language-sh">git push --set-upstream origin test</code></pre> </li> <li> <p>查看当前的origin</p> <pre><code class="language-sh">git remote -v</code></pre> </li> <li> <p>删除远程分支</p> <pre><code class="language-sh">git push origin --delete <branchName> git push origin :<branchName></code></pre> </li> <li> <p>查看状态</p> <pre><code class="language-sh">git remote show origin</code></pre> </li> <li> <p>删除不存在对应远程分支的本地分支</p> <pre><code class="language-sh">git remote prune origin # stale不新鲜的;prune修剪,削减 git fetch -p</code></pre> </li> <li> <p>重命名本地分支(devel -> develop)</p> <pre><code class="language-sh">git branch -m devel develop</code></pre> </li> <li> <p>推送本地分支</p> <pre><code class="language-sh">git push origin develop</code></pre> </li> </ul>
详情
<h2>一、关于Google AdSense</h2> <p>上个星期我为自己的博客开通了Google Adsense。一方面是想学学Google AdSense;另一方面看看能有多少收入。 一共为了两个网站开通Google Adsense,一个已经顺利通过了;一个没有审核通过。没有通过的原因是<code>We’ve found some policy violations on your site which means your site isn’t ready to show ads yet. Make sure your site follows the AdSense Program Policies.</code> 现在还没有时间去修改网站。</p> <h2>二、注册 Google AdSense</h2> <p>注册 Google AdSense 是很容易的。前提是需一个你自己的网站和一个 Google 邮箱。按照注册页面提示填写所需信息即可。注册地址:<a href="https://www.google.com/adsense/signup/new/lead">https://www.google.com/adsense/signup/new/lead</a> 注册帮助文档:<a href="https://support.google.com/adsense/answer/7402253">https://support.google.com/adsense/answer/7402253</a></p> <h2>三、连接网站和 Google AdSense</h2> <ol> <li>上传 <code>ads.txt</code> 到网站根目录。帮助文档 <a href="https://support.google.com/adsense/answer/7532444?hl=zh-Hans">https://support.google.com/adsense/answer/7532444?hl=zh-Hans</a></li> <li>创建广告。 AdSense 提供了两种方式的广告。一种Auto ads(自动广告),一般是要复制一段JavaScript代码放置页面的 head 标签之间,AdSense 会分析你页面,在页面合适的位置放置广告。另一种是Ad unit(广告单元),你可以创建多个不同的广告单元,然后应用到网站的不同页面,推荐这种方式,这种方式更容易适应你的网站风格(不会破坏网页布局)。</li> </ol> <p>一开始,我用的是Auto ads,发现它撑破了页面的布局,极度不好看。Ad unit 有三种类型,分别为Square,Horizontal 和 Vertical。要按照网站布局方式选择。我选择了Horizontal的,因为它适合我的网页布局。 <img src="//www.pcdeng.com/uploads/ad-unit1.png" alt="Adunit1" /></p> <p>创建好 Ad unit 后就可以复制代码到你想要放置的地方。 <img src="//www.pcdeng.com/uploads/adunit2.png" alt="Adunit2" /></p> <p>例如我的</p> <pre><code class="language-javascript"><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- horizontal --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-2862993259615109" data-ad-slot="6046279191" data-ad-format="auto" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script></code></pre> <h2>四、运行效果</h2> <p>经过两周的运行后,收益如下: <img src="//www.pcdeng.com/uploads/earnings.png" alt="收益" /> 注意:收益要满100刀才可以提现。</p> <h2>五、总结</h2> <p>通过开通Google AdSense 账户,我对它有了初步的认识。对其它网站提供的广告也没有那么反感了,希望看到这篇文章的你也不要反感这个网站的广告。</p>
详情